
14.6 系统前端
本项目的前端功能是通过Vue实现的,建立和项目后端API的连接,实现ChatGPT聊天页面功能。在本节的内容中,将详细讲解本项目前端模块的实现过程。
14.6.1 设置代理
编写文件proxy.ts创建Vite开发服务器代理的函数,其作用是在开发环境中将来自前端应用程序的HTTP请求转发到后端API服务器,以便项目测试和调试。在文件文件proxy.ts中定义了一个名为 createViteProxy 的函数,该函数接受如下两个参数:
- isOpenProxy:一个布尔值,指示代理是否打开。当代理关闭时,函数将返回 undefined。
- viteEnv:一个包含当前Vite环境变量的对象,例如 VITE_APP_API_BASE_URL 等。
文件proxy.ts的主要实现代码如下所示。
import type { ProxyOptions } from 'vite' export function createViteProxy(isOpenProxy: boolean, viteEnv: ImportMetaEnv) { if (!isOpenProxy) return const proxy: Record<string, string | ProxyOptions> = { '/api': { target: viteEnv.VITE_APP_API_BASE_URL, changeOrigin: true, rewrite: path => path.replace('/api/', '/'), }, } return proxy }
复制
如果打开代理,函数createViteProxy()将创建一个名为 proxy 的对象,并使用 viteEnv.VITE_APP_API_BASE_URL 作为后端API服务器的基本URL。然后,它将设置 /api 路径的代理规则,以便将来自前端应用程序的HTTP请求重定向到后端API服务器。同时,还可以通过 rewrite 属性将URL中的路径重写为API服务器的实际路径,例如将 /api/users 重写为 /users。
最后,它将返回代理配置对象(proxy),供Vite开发服务器使用。
14.6.2 HTTP请求
编写文件frontend\src\api\index.ts,功能是在前台页面向后台服务器发送HTTP请求,主要实现代码如下所示。
export function fetchChatAPI<T = any>( prompt: string, options?: { conversationId?: string; parentMessageId?: string }, signal?: GenericAbortSignal, ) { return post<T>({ url: '/chat', data: { prompt, options }, signal, }) } export function fetchChatConfig<T = any>() { return post<T>({ url: '/config', }) } export function fetchChatAPIProcess<T = any>( params: { prompt: string options?: { conversationId?: string; parentMessageId?: string } baseURI?: string accessToken?: string isGPT4?: boolean signal?: GenericAbortSignal onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void }, ) { const settingStore = useSettingStore() return post<T>({ url: '/chat-process', data: { prompt: params.prompt, options: params.options, systemMessage: settingStore.systemMessage, baseURI: params.baseURI, accessToken: params.accessToken, isGPT4: params.isGPT4 }, signal: params.signal, onDownloadProgress: params.onDownloadProgress, }) } export function fetchSession<T>() { return post<T>({ url: '/session', }) } export function fetchVerify<T>(token: string) { return post<T>({ url: '/verify', data: { token }, }) }
复制
在上述代码中实现了用于向服务器发送HTTP请求的方法,它们使用库axios来执行网络请求,并返回Promise对象以便在异步环境中使用。对上述方法的具体说明如下:
- 方法fetchChatAPI():向 /chat 接口发送POST请求,传递一个名为 prompt 的字符串参数和一个可选的包含 conversationId 和 parentMessageId 属性的对象,用于获取聊天机器人的回复。该函数返回一个泛型类型 T 的Promise对象,可以通过 then 方法处理响应结果。
- 方法fetchChatConfig<T>():向 /config 接口发送POST请求,用于获取聊天机器人的配置信息。该函数返回一个泛型类型 T 的Promise对象,可以通过 then 方法处理响应结果。
- 方法fetchChatAPIProcess<T>(params: {...}):向 /chat-process 接口发送POST请求,传递一个包含多个参数的对象,用于获取聊天机器人的回复和处理过程。该函数返回一个泛型类型 T 的Promise对象,可以通过 then 方法处理响应结果。
- 方法fetchSession<T>():向 /session 接口发送POST请求,获取当前用户的会话信息。该函数返回一个泛型类型 T 的Promise对象,可以通过 then 方法处理响应结果。
- 方法fetchVerify<T>(token: string):向 /verify 接口发送POST请求,传递一个名为 token 的字符串参数,用于验证用户的身份。该函数返回一个泛型类型 T 的Promise对象,可以通过 then 方法处理响应结果。
上述方法都是基于 post 方法封装而成的,其中使用了一些默认请求配置,例如基本URL、请求头、超时时间等。此外,方法fetchChatAPIProcess()还支持在下载过程中获取进度信息,并接受一个可取消的 signal 参数,以便在需要时取消请求。
在实际应用程序中,我们可能需要根据具体业务需求定义更多的HTTP请求函数,并针对不同的接口和数据类型进行适当的错误处理和数据转换。
14.6.3 ChatGPT聊天界面侧边栏
编写文件frontend/src/views/chat/layout/sider/index.vue实现ChatGPT聊天界面的左侧边栏功能,主要实现代码如下所示。
const appStore = useAppStore() const chatStore = useChatStore() const { isMobile } = useBasicLayout() const show = ref(false) const collapsed = computed(() => appStore.siderCollapsed) function handleAdd() { chatStore.addHistory({ title: 'New Chat', uuid: Date.now(), isEdit: false }) if (isMobile.value) appStore.setSiderCollapsed(true) } function handleUpdateCollapsed() { appStore.setSiderCollapsed(!collapsed.value) } const getMobileClass = computed<CSSProperties>(() => { if (isMobile.value) { return { position: 'fixed', zIndex: 50, } } return {} }) const mobileSafeArea = computed(() => { if (isMobile.value) { return { paddingBottom: 'env(safe-area-inset-bottom)', } } return {} }) watch( isMobile, (val) => { appStore.setSiderCollapsed(val) }, { immediate: true, flush: 'post', }, ) </script> <template> <NLayoutSider :collapsed="collapsed" :collapsed-width="0" :width="260" :show-trigger="isMobile ? false : 'arrow-circle'" collapse-mode="transform" position="absolute" bordered :style="getMobileClass" @update-collapsed="handleUpdateCollapsed" > <div class="flex flex-col h-full" :style="mobileSafeArea"> <main class="flex flex-col flex-1 min-h-0"> <div class="p-4"> <NButton dashed block @click="handleAdd"> {{ $t('chat.newChatButton') }} </NButton> </div> <div class="flex-1 min-h-0 pb-4 overflow-hidden"> <List /> </div> <div class="p-4"> <NButton block @click="show = true"> {{ $t('store.siderButton') }} </NButton> </div> </main> <Footer /> </div> </NLayoutSider> <template v-if="isMobile"> <div v-show="!collapsed" class="fixed inset-0 z-40 bg-black/40" @click="handleUpdateCollapsed" /> </template> <PromptStore v-model:visible="show" /> </template>
复制
上述代码使用了多个Vue.js实用工具,例如使用computed、ref、watch等来管理侧边栏的状态和显示内容。在侧边栏中还包括了一个“新建聊天”按钮,用于创建新的聊天会话,并在侧边栏中显示已有的聊天历史记录。同时,在移动设备上,该组件还会自动适应安全区域,并提供了一个可折叠的侧边栏菜单。此外,在侧边栏中还包括了一个Footer组件,用于显示底部的版权信息。最后,该组件还引用了PromptStore组件,并在需要时显示该组件的模态对话框。