feat: 新增中断但是未测试

This commit is contained in:
何嘉悦 2025-06-03 20:26:55 +08:00
parent 53644936d2
commit b2574805fd
10 changed files with 39 additions and 12 deletions

BIN
dist.rar

Binary file not shown.

View File

@ -2,7 +2,7 @@ import type { ChatMessageVo, GetChatListParams, SendDTO } from './types';
import { get, post } from '@/utils/request'; import { get, post } from '@/utils/request';
// 发送消息 // 发送消息
export const send = (data: SendDTO) => post<null>('/chat/send', data).stream(); export const send = (data: SendDTO) => post<null>('/chat/send', data);
// 新增对应会话聊天记录 // 新增对应会话聊天记录
export function addChat(data: ChatMessageVo) { export function addChat(data: ChatMessageVo) {

View File

@ -1,2 +1,4 @@
export * from './auth'; export * from './auth';
export * from './chat';
export * from './model';
export * from './session'; export * from './session';

View File

@ -3,7 +3,7 @@
import type { ConversationItem } from 'vue-element-plus-x/types/Conversations'; import type { ConversationItem } from 'vue-element-plus-x/types/Conversations';
import type { ChatSessionVo } from '@/api/session/types'; import type { ChatSessionVo } from '@/api/session/types';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { get_session } from '@/api/session'; import { get_session } from '@/api';
import logo from '@/assets/images/logo.png'; import logo from '@/assets/images/logo.png';
import SvgIcon from '@/components/SvgIcon/index.vue'; import SvgIcon from '@/components/SvgIcon/index.vue';
import Collapse from '@/layouts/components/Header/components/Collapse.vue'; import Collapse from '@/layouts/components/Header/components/Collapse.vue';

View File

@ -1,5 +1,6 @@
<!-- 每个回话对应的聊天内容 --> <!-- 每个回话对应的聊天内容 -->
<script setup lang="ts"> <script setup lang="ts">
import type { HookFetchRequest } from 'node_modules/hook-fetch/types/utils';
import type { AnyObject } from 'typescript-api-pro'; import type { AnyObject } from 'typescript-api-pro';
import type { Sender } from 'vue-element-plus-x'; import type { Sender } from 'vue-element-plus-x';
import type { BubbleProps } from 'vue-element-plus-x/types/Bubble'; import type { BubbleProps } from 'vue-element-plus-x/types/Bubble';
@ -7,7 +8,7 @@ import type { BubbleListInstance } from 'vue-element-plus-x/types/BubbleList';
import type { FilesCardProps } from 'vue-element-plus-x/types/FilesCard'; import type { FilesCardProps } from 'vue-element-plus-x/types/FilesCard';
import type { ThinkingStatus } from 'vue-element-plus-x/types/Thinking'; import type { ThinkingStatus } from 'vue-element-plus-x/types/Thinking';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { send } from '@/api/chat/index'; import { send } from '@/api';
import FilesSelect from '@/components/FilesSelect/index.vue'; import FilesSelect from '@/components/FilesSelect/index.vue';
import ModelSelect from '@/components/ModelSelect/index.vue'; import ModelSelect from '@/components/ModelSelect/index.vue';
import { useChatStore } from '@/stores/modules/chat'; import { useChatStore } from '@/stores/modules/chat';
@ -29,11 +30,19 @@ const modelStore = useModelStore();
const filesStore = useFilesStore(); const filesStore = useFilesStore();
const userStore = useUserStore(); const userStore = useUserStore();
//
const avatar = computed(() => {
const userInfo = userStore.userInfo;
return userInfo?.avatar || 'https://avatars.githubusercontent.com/u/76239030?v=4';
});
const inputValue = ref(''); const inputValue = ref('');
const senderRef = ref<InstanceType<typeof Sender> | null>(null); const senderRef = ref<InstanceType<typeof Sender> | null>(null);
const bubbleItems = ref<MessageItem[]>([]); const bubbleItems = ref<MessageItem[]>([]);
const bubbleListRef = ref<BubbleListInstance | null>(null); const bubbleListRef = ref<BubbleListInstance | null>(null);
const isLoading = ref(false); const isLoading = ref(false);
//
let sendRequest: HookFetchRequest<any, any> | null = null;
watch( watch(
() => route.params?.id, () => route.params?.id,
@ -125,7 +134,7 @@ async function startSSE(chatContent: string) {
// BubbleList // BubbleList
bubbleListRef.value?.scrollToBottom(); bubbleListRef.value?.scrollToBottom();
const res = send({ sendRequest = send({
messages: bubbleItems.value messages: bubbleItems.value
.filter((item: any) => item.role === 'user') .filter((item: any) => item.role === 'user')
.map((item: any) => ({ .map((item: any) => ({
@ -137,7 +146,7 @@ async function startSSE(chatContent: string) {
model: modelStore.currentModelInfo.modelName ?? '', model: modelStore.currentModelInfo.modelName ?? '',
}); });
for await (const chunk of res) { for await (const chunk of sendRequest.stream()) {
handleDataChunk(chunk.result as AnyObject); handleDataChunk(chunk.result as AnyObject);
} }
} }
@ -154,13 +163,23 @@ async function startSSE(chatContent: string) {
} }
} }
//
async function cancelSSE() {
sendRequest?.abort();
isLoading.value = false;
//
if (bubbleItems.value.length) {
bubbleItems.value[bubbleItems.value.length - 1].typing = false;
}
}
// - // -
function addMessage(message: string, isUser: boolean) { function addMessage(message: string, isUser: boolean) {
const i = bubbleItems.value.length; const i = bubbleItems.value.length;
const obj: MessageItem = { const obj: MessageItem = {
key: i, key: i,
avatar: isUser avatar: isUser
? 'https://avatars.githubusercontent.com/u/76239030?v=4' ? avatar.value
: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png', : 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
avatarSize: '32px', avatarSize: '32px',
role: isUser ? 'user' : 'system', role: isUser ? 'user' : 'system',
@ -228,6 +247,7 @@ watch(
allow-speech allow-speech
:loading="isLoading" :loading="isLoading"
@submit="startSSE" @submit="startSSE"
@cancel="cancelSSE"
> >
<template #header> <template #header>
<div class="sender-header p-12px pt-6px pb-0px"> <div class="sender-header p-12px pt-6px pb-0px">

View File

@ -1,11 +1,17 @@
import type { ChatMessageVo } from '@/api/chat/types'; import type { ChatMessageVo } from '@/api/chat/types';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { getChatList } from '@/api/chat'; import { getChatList } from '@/api';
import { useUserStore } from './user'; import { useUserStore } from './user';
export const useChatStore = defineStore('chat', () => { export const useChatStore = defineStore('chat', () => {
const userStore = useUserStore(); const userStore = useUserStore();
// 用户头像
const avatar = computed(() => {
const userInfo = userStore.userInfo;
return userInfo?.avatar || 'https://avatars.githubusercontent.com/u/76239030?v=4';
});
// 是否开启深度思考 // 是否开启深度思考
const isDeepThinking = ref<boolean>(false); const isDeepThinking = ref<boolean>(false);
@ -27,7 +33,7 @@ export const useChatStore = defineStore('chat', () => {
// variant: 'shadow', // variant: 'shadow',
// shape: 'corner', // shape: 'corner',
avatar: isUser avatar: isUser
? 'https://avatars.githubusercontent.com/u/76239030?v=4' ? avatar
: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png', : 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
avatarSize: '32px', avatarSize: '32px',
typing: false, typing: false,

View File

@ -1,6 +1,6 @@
import type { GetSessionListVO } from '@/api/model/types'; import type { GetSessionListVO } from '@/api/model/types';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { getModelList } from '@/api/model/index'; import { getModelList } from '@/api';
// 模型管理 // 模型管理
export const useModelStore = defineStore('model', () => { export const useModelStore = defineStore('model', () => {

View File

@ -9,7 +9,7 @@ import {
get_session, get_session,
get_session_list, get_session_list,
update_session, update_session,
} from '@/api/session'; } from '@/api';
import { useUserStore } from './user'; import { useUserStore } from './user';
export const useSessionStore = defineStore('session', () => { export const useSessionStore = defineStore('session', () => {

View File

@ -3,7 +3,7 @@
// Generated by unplugin-vue-components // Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
// biome-ignore lint: disable // biome-ignore lint: disable
export {}; export {}
/* prettier-ignore */ /* prettier-ignore */
declare module 'vue' { declare module 'vue' {

View File

@ -5,7 +5,6 @@ interface ImportMetaEnv {
readonly VITE_WEB_TITLE_EN: string; readonly VITE_WEB_TITLE_EN: string;
readonly VITE_WEB_ENV: string; readonly VITE_WEB_ENV: string;
readonly VITE_WEB_BASE_API: string; readonly VITE_WEB_BASE_API: string;
readonly VITE_BUILD_COMPRESS: string;
readonly VITE_API_URL: string; readonly VITE_API_URL: string;
} }