123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- <script setup>
- import { ref, unref, computed, onMounted } from 'vue';
- import { useMessage } from 'naive-ui';
- import { BaseButton, RecodeCardItem, TheSubMenu, TheChatView, ChatWelcome } from '@/components';
- import { ChatAsk, ChatAnswer, ChatInput } from '@/components/Chat';
- import { chatApi } from '@/api/chat';
- import { useInfinite } from '@/composables/useInfinite';
- import { useScroll } from '@/composables/useScroll';
- import { useChat } from '@/composables/useChat';
- import { useRecommend } from '@/composables/useRecommend';
- // TODO: 如果这里的key不一样,将会在拆一层组件出来 - list
- const { recordList, isFetching, onScrolltolower, onReset, addHistoryRecord } = useInfinite({model: 0});
- const { scrollRef, scrollToBottom, scrollToBottomIfAtBottom } = useScroll();
- const { chatDataSource, addChat, updateChat, clearChat } = useChat();
- const { recommendList } = useRecommend({type: 0});
- const message = useMessage();
- const isLoading = ref(false);
- const currenSessionId = ref(null);
- const isExistInHistory = computed(() => (recordList.value.findIndex(({ sessionId: sId }) => sId === unref(currenSessionId)) === -1));
- // 新建对话
- const handleCreateDialog = async () => {
- message.destroyAll();
- if (unref(isLoading)) {
- return message.warning('当前对话生成中');
- }
- if (!unref(chatDataSource).length) {
- return message.info('已切换最新会话');
- }
-
- clearChat();
- }
- // 查询对话详情
- const handleChatDetail = async ({ sessionId }) => {
- isLoading.value = false;
- const { data } = await chatApi.getAnswerHistoryDetail({ sessionId });
- chatDataSource.value = data.map(({ createTime, sessionId, question, answer }) => ({
- createTime,
- sessionId,
- question,
- answer,
- loading: false
- }));
- currenSessionId.value = sessionId;
- scrollToBottom();
- }
- const onRegenerate = async ({ question, realQuestion }) => {
- const sessionId = unref(currenSessionId);
- const params = {
- data: {
- sessionId,
- question: realQuestion || question,
- },
- onDownloadProgress: ({ event }) => {
- const xhr = event.target;
- const { responseText: answer } = xhr;
- updateChat({
- sessionId,
- question,
- answer,
- loading: true,
- delayLoading: false
- })
- scrollToBottomIfAtBottom();
- }
- }
- try {
- const { data: answer } = await chatApi.getChatStream(params);
- updateChat({
- sessionId,
- question,
- answer,
- loading: false,
- delayLoading: false
- })
- }
- finally {
- isLoading.value = false;
- }
- }
- // 提交问题
- const handleSubmit = async (question, realQuestion = '') => {
- // 用于模拟 - 内容生成前置等待状态
-
- if (unref(isExistInHistory)) {
- const { data: sessionId } = await chatApi.getChatSessionTag();
- currenSessionId.value = sessionId;
- }
- isLoading.value = true;
- addChat({
- sessionId: unref(currenSessionId),
- question,
- realQuestion,
- answer: '',
- loading: true,
- delayLoading: true
- })
- scrollToBottom();
- setTimeout(() => onRegenerate({ question, realQuestion }), 2 * 1000);
- }
- // 处理推荐问题
- const handleWelcomeRecommend = ({ question, realQuestion }) => {
- handleSubmit( question, realQuestion );
- }
- // 删除历史对话
- const handeChatDelete = async (id) => {
- await chatApi.deleteHistory(id);
- onReset();
- clearChat();
- message.success('删除成功');
- }
- </script>
- <template>
- <section class="flex items-start h-full">
- <TheSubMenu title="历史记录" @scrollToLower="onScrolltolower" :loading="isFetching">
- <template #top>
- <div class="create-btn px-[11px] pb-[22px]">
- <BaseButton @click="handleCreateDialog">新建对话</BaseButton>
- </div>
- </template>
- <div class="pr-[4px] text-[#5e5e5e]">
- <RecodeCardItem
- v-for="item in recordList"
- :key="item.sessionId"
- :title="item.question"
- :time="item.createTime"
- :data-item="item"
- @on-click="handleChatDetail"
- @on-delete="handeChatDelete"
- />
- </div>
- </TheSubMenu>
- <TheChatView ref="scrollRef">
- <ChatWelcome title="您好,我是LibraAI专家问答" card-title="您可以试着问我:"
- :sub-title="[
- '期待与您一同规划和完成未来的工作。有任何重点或需讨论的事项,随时告诉我。'
- ]"
- :card-content="recommendList"
- v-if="!chatDataSource.length"
- @on-click="handleWelcomeRecommend"
- />
- <div class="conversation-item" v-if="chatDataSource.length">
- <template v-for="item in chatDataSource" :key="item.id">
- <ChatAsk :content="item.question"></ChatAsk>
- <ChatAnswer :content="item.answer" :loading="item.loading" :delay-loading="item.delayLoading"></ChatAnswer>
- </template>
- </div>
- <template #footer>
- <ChatInput @on-click="handleSubmit" @on-enter="handleSubmit" v-model:loading="isLoading"></ChatInput>
- </template>
- </TheChatView>
- </section>
- </template>
|