亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

vue3實(shí)現(xiàn)ai聊天對(duì)話框功能

 更新時(shí)間:2024年12月17日 10:57:55   作者:正小安  
這篇文章主要介紹了vue3實(shí)現(xiàn)ai聊天對(duì)話框功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧

各功能部分學(xué)習(xí)

input輸入

使用@keydown 鍵盤進(jìn)行操作,回車和點(diǎn)擊一樣進(jìn)行搜索

@keydown.enter.exact.prevent="handleSend"
@keydown.enter.shift.exact="newline"

按鈕 loading 加載圖標(biāo):這里設(shè)置 template 插槽

<el-button
  type="primary"
  :loading="loading"
  @click="handleSend"
  >
  <template #icon>
    <el-icon><Position /></el-icon>
  </template>
  發(fā)送
</el-button>

職責(zé)分離,子組件完成頁(yè)面搭建,需要用到哪些邏輯,再通過(guò) emit 通信到父組件由父組件完成。整個(gè)頁(yè)面涉及到一個(gè)多個(gè)組件使用的 loading 屬性,由 settings 倉(cāng)庫(kù)存儲(chǔ)。

message對(duì)話框

簡(jiǎn)單的一行代碼使用戶消息放在右側(cè)

  &.message-user {
    flex-direction: row-reverse;
    //翻轉(zhuǎn)實(shí)現(xiàn)用戶布局在右側(cè)
    .message-content {
      align-items: flex-end;
    }
  }

換行屬性white-space: pre-wrap;保留源代碼中的空白字符和換行符,否則為white-space: normal;(默認(rèn)值):合并連續(xù)的空白字符,忽略源代碼中的換行符,自動(dòng)換行

settings設(shè)置面板

  • 設(shè)置屬性都設(shè)置在倉(cāng)庫(kù)里,用于全局。
  • 樣式命名w-full這總可以通俗易懂的看出是寬度占滿。
  • 如何在 stlye 中修改 elementPlus 原本的樣式。
  • elementPlus 設(shè)置暗黑模式
//App.vue
<template>
  <div :class="{ 'dark': isDarkMode }">
  <router-view />
  </div>
  </template>
  <script setup>
  import { computed } from 'vue'
import { useSettingsStore } from './stores/settings'
const settingsStore = useSettingsStore()
const isDarkMode = computed(() => settingsStore.isDarkMode)
  </script>
//dark.scss
html.dark {
  // Element Plus 暗黑模式變量覆蓋
  --el-bg-color: var(--bg-color);
  --el-bg-color-overlay: var(--bg-color-secondary);
  --el-text-color-primary: var(--text-color-primary);
  --el-text-color-regular: var(--text-color-regular);
  --el-border-color: var(--border-color);
  // Element Plus 組件暗黑模式樣式覆蓋
  .el-input-number {
    --el-input-number-bg-color: var(--bg-color-secondary);
    --el-input-number-text-color: var(--text-color-primary);
  }
  .el-select-dropdown {
    --el-select-dropdown-bg-color: var(--bg-color);
    --el-select-dropdown-text-color: var(--text-color-primary);
  }
  .el-slider {
    --el-slider-main-bg-color: var(--primary-color);
  }
}
//main.js
import './assets/styles/dark.scss'

使用 scss 設(shè)置暗黑模式:

1. 使用pinia狀態(tài)管理。
2. 在設(shè)置面板點(diǎn)擊切換,觸發(fā)toggleDarkMode動(dòng)作(在pinia中設(shè)置),切換isDarlMode狀態(tài),并更新跟元素的data-theme屬性。
3. 暗黑模式的樣式設(shè)置在scss變量中

當(dāng)刷新后樣式會(huì)變回白天模式,但是這時(shí)候settings中選中的還是黑夜模式,這是為什么?

答:雖然設(shè)置存儲(chǔ)在了 localStorage 中,但是在頁(yè)面刷新后沒有正確地初始化深色模式的樣式。我們需要在應(yīng)用啟動(dòng)時(shí)立即應(yīng)用存儲(chǔ)的主題設(shè)置。

解決辦法:給 App.vue 加上掛載時(shí)就進(jìn)行一次設(shè)置。

onMounted(() => {
  // 根據(jù)存儲(chǔ)的設(shè)置初始化主題
  document.documentElement.setAttribute('data-theme', settingsStore.isDarkMode ? 'dark' : 'light')
})

傳輸數(shù)據(jù)

axios、 XMLHttpRequest 、fetch

以下是 Axios、XMLHttpRequestFetch 在發(fā)送 HTTP 請(qǐng)求時(shí)的對(duì)比,包括用法、性能、兼容性和適用場(chǎng)景的詳細(xì)分析:

前后端通信所用技術(shù)對(duì)比

AI 對(duì)話需要到流式響應(yīng)處理,通信技術(shù)最終采用 fetch。

場(chǎng)景AxiosXMLHttpRequestFetch
快速開發(fā)簡(jiǎn)單請(qǐng)求優(yōu)秀,語(yǔ)法簡(jiǎn)潔不適合,代碼繁瑣良好,語(yǔ)法簡(jiǎn)潔
全局配置需求支持,提供 defaults 配置不支持需要手動(dòng)實(shí)現(xiàn)
請(qǐng)求/響應(yīng)攔截處理原生支持?jǐn)r截器不支持需要手動(dòng)實(shí)現(xiàn)
上傳/下載進(jìn)度監(jiān)聽不支持支持不支持
兼容舊版瀏覽器支持,通過(guò) polyfill支持不支持
流式響應(yīng)處理不支持不支持支持(結(jié)合 ReadableStream
輕量級(jí)需求適合不適合適合

實(shí)現(xiàn)流式數(shù)據(jù)處理

1. 項(xiàng)目實(shí)現(xiàn)代碼

  • 發(fā)送請(qǐng)求
    在 src/utils/api.js 中,chatApi.sendMessage 方法負(fù)責(zé)發(fā)送請(qǐng)求。根據(jù) stream 參數(shù)的值,決定是否請(qǐng)求流式響應(yīng)。
async sendMessage(messages, stream = false) {
    // ...
    const response = await fetch(`${API_BASE_URL}/chat/completions`, {
        method: 'POST',
        headers: {
            ...createHeaders(),
            ...(stream && { 'Accept': 'text/event-stream' }) // 如果是流式響應(yīng),添加相應(yīng)的 Accept 頭
        },
        body: JSON.stringify(payload)
    })
    // ...
    if (stream) {
        return response // 對(duì)于流式響應(yīng),直接返回 response 對(duì)象
    }
    // ...
}

處理流式響應(yīng)
在 src/utils/messageHandler.js 中,processStreamResponse 方法負(fù)責(zé)處理流式響應(yīng)。它使用 ReadableStream 的 getReader 方法逐步讀取數(shù)據(jù),并使用 TextDecoder 解碼數(shù)據(jù)。 

  • 讀取流數(shù)據(jù)
  • 解碼數(shù)據(jù)塊
  • 處理解碼后的數(shù)據(jù):先拆分為行(數(shù)組),再轉(zhuǎn)換為json字符串,再轉(zhuǎn)換為js對(duì)象,提取出對(duì)象中content內(nèi)容,更新message、更新token使用量
async processStreamResponse(response, { updateMessage, updateTokenCount }) {
  try {
      let fullResponse = '';
      const reader = response.body.getReader();
      const decoder = new TextDecoder();
          // 1.讀取流數(shù)據(jù)
      while (true) {
          const { done, value } = await reader.read();
          if (done) {
              console.log('流式響應(yīng)完成');
              break;
          }
          //2.解碼數(shù)據(jù)塊
          const chunk = decoder.decode(value);  //這里每一個(gè)chunk是一個(gè)可能包含多個(gè)數(shù)組
          //3.處理解碼后的數(shù)據(jù),先拆分為行(數(shù)組),再轉(zhuǎn)換為json字符串,再轉(zhuǎn)換為js對(duì)象,提取出對(duì)象中content內(nèi)容,更新message、更新token使用量
          // 3.1 拆分為行
          const lines = chunk.split('\n').filter(line => line.trim() !== '');
          for (const line of lines) {
              if (line.includes('data: ')) {
          // 3.2 轉(zhuǎn)換為json字符串
                  const jsonStr = line.replace('data: ', '');
                  // 檢查是否結(jié)束
                  if (jsonStr === '[DONE]') {
                      console.log('流式響應(yīng)完成,讀取完畢');
                      continue;
                  }
          // 3.3 轉(zhuǎn)換為js對(duì)象
                  try {
                      const jsData = JSON.parse(jsonStr);
                      if (jsData.choices[0].delta.content) {
                          const content = jsData.choices[0].delta.content;
          //3.4 提取出對(duì)象中content內(nèi)容,更新message
                          fullResponse += content;
                          updateMessage(fullResponse);
                      }
          // 3.5更新token使用量
                      if (jsData.usage) {
                          updateTokenCount(jsData.usage);
                      }
                  } catch (e) {
                      console.error('解析JSON失敗:', e);
                  }
              }
          }
      }
  } catch (error) {
      console.error('流處理錯(cuò)誤:', error);
      throw error;
  }
},

更新界面
在 src/views/ChatView.vue 中,handleSend 方法調(diào)用 processStreamResponse,并通過(guò)回調(diào)函數(shù) updateMessage 和 updateTokenCount 更新界面。

const handleSend = async (content) => {
    // ...
    try {
        const response = await chatApi.sendMessage(
            messages.value.slice(0, -1).map(m => ({
                role: m.role,
                content: m.content
            })),
            settingsStore.streamResponse
        );
        if (settingsStore.streamResponse) {
          // 這里使用了await不會(huì)將這個(gè)變化為同步嗎,我了解到的使用await后會(huì)等之后的函數(shù)調(diào)用完再執(zhí)行之后的代碼,是這樣嗎?
            await messageHandler.processStreamResponse(response, {
                updateMessage: (content) => chatStore.updateLastMessage(content),
                updateTokenCount: (usage) => chatStore.updateTokenCount(usage)
            });
        }
        // ...
    } catch (error) {
        chatStore.updateLastMessage('抱歉,發(fā)生了錯(cuò)誤,請(qǐng)稍后重試。')
    } finally {
        chatStore.isLoading = false
    }
}

2. 知識(shí)點(diǎn)

2.1. 疑問及解答

幾個(gè)核心概念:1.ReadableStream,2.getReader()算是ReadableStream的一個(gè)方法嗎,3.reader.read(),4.Uint8Array ,5. Streams API,6.TextDecoder
(由 fetch 返回的response.body 是ReadableStream對(duì)象引申出來(lái)的問題) fetch 處理響應(yīng)有哪些方式?類型又是什么 ?

2.1.1. 解答的理解

有關(guān)流式涉及到的概念

ReadableStream是 StreamsAPI 的核心對(duì)象 之一,這里涉及到是因?yàn)榫W(wǎng)絡(luò)請(qǐng)求的response.body是一個(gè)ReadableStream對(duì)象。

深入補(bǔ)充:Streams API是 Web API ,用于流方式處理數(shù)據(jù) getReader()ReadableStream的一個(gè)方法,(因?yàn)?1 所以response.body也有這個(gè)方法)

這個(gè)方法會(huì)返回一個(gè) reader 對(duì)象(這里是簡(jiǎn)稱),它可以逐塊讀取流中的數(shù)據(jù),提供對(duì)流的完全控制 (注:使用 getReader 后,其他地方便無(wú)法訪問流,意思是只有它返回的 reader 對(duì)象可以訪問流)

reader 對(duì)象有一個(gè)方法reader.read() 異步讀取流中的數(shù)據(jù)塊 。返回值如下:

{ done: true/false, value: Uint8Array | undefined }
  • done: 如果為 true,表示流已讀取完畢。
  • value: 當(dāng)前讀取的塊數(shù)據(jù),通常是 Uint8Array, 每個(gè)元素占用 1 個(gè)字節(jié) 。

Uint8Array 是一種 類型化數(shù)組,高效地處理原始二進(jìn)制數(shù)據(jù),如文件塊、圖像、網(wǎng)絡(luò)響應(yīng) 。

對(duì)二進(jìn)制數(shù)據(jù)的處理:

  • Uint8Array轉(zhuǎn)換為字符串,使用TextDecoder,編碼如 utf-8、utf-16。使用它的decode方法將字節(jié)數(shù)據(jù)轉(zhuǎn)換為字符串。
  • 轉(zhuǎn)換為圖像/視頻,使用Blob,設(shè)置類型 image 或者 video,再將生成的 blob 對(duì)象轉(zhuǎn)換為 URL,即可使用。

總結(jié)圖示:

Streams API  
├── ReadableStream(response.body類型) → 提供流式數(shù)據(jù)塊
│    ├── getReader() → 獲取 reader
│    │    └── reader.read() → 讀取單個(gè)數(shù)據(jù)塊 {done, value}
│    │
│    └── 數(shù)據(jù)塊通常是 Uint8Array 類型
│
└── TextDecoder → 解碼 Uint8Array 為字符串
└── Blob → 解碼 Uint8Array 為圖像視頻

fetch 響應(yīng)方法極其類型

方法返回類型常見場(chǎng)景
response.text()Promise<string>文本、HTML
response.json()Promise<Object>JSON API 響應(yīng)
response.blob()Promise<Blob>圖片、視頻、文件下載
response.arrayBuffer()Promise<ArrayBuffer>二進(jìn)制數(shù)據(jù)、文件解析
response.formData()Promise<FormData>表單響應(yīng)(少見)
response.bodyReadableStream實(shí)時(shí)處理、進(jìn)度跟蹤

注意:

fetch 的響應(yīng)體只能被讀取一次 (即:不能同時(shí)調(diào)用 response.json()response.text()等 )

即使響應(yīng)有錯(cuò)誤狀態(tài)(如 404),fetch 不會(huì)拋出異常,需要手動(dòng)檢查 response.ok。如下代碼處理方式:

let response = await fetch('https://example.com');
if (!response.ok) {
  throw new Error(`HTTP error! status: ${response.status}`);
}

完整代碼見:github

到此這篇關(guān)于vue3實(shí)現(xiàn)ai聊天對(duì)話框的文章就介紹到這了,更多相關(guān)vue3 ai聊天對(duì)話框內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用axios請(qǐng)求接口,幾種content-type的區(qū)別詳解

    使用axios請(qǐng)求接口,幾種content-type的區(qū)別詳解

    今天小編就為大家分享一篇使用axios請(qǐng)求接口,幾種content-type的區(qū)別詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-10-10
  • elementUI?checkBox報(bào)錯(cuò)Cannot read property 'length' of undefined解決

    elementUI?checkBox報(bào)錯(cuò)Cannot read property &ap

    這篇文章主要為大家介紹了elementUI?checkBox報(bào)錯(cuò)Cannot read property 'length' of undefined的解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Vue使用Sentry實(shí)現(xiàn)錯(cuò)誤監(jiān)控

    Vue使用Sentry實(shí)現(xiàn)錯(cuò)誤監(jiān)控

    Sentry?是一款功能強(qiáng)大的開源錯(cuò)誤監(jiān)控服務(wù),廣泛用于追蹤和修復(fù)應(yīng)用中的異常情況,本文將詳細(xì)介紹如何在?Vue?應(yīng)用中集成和使用?Sentry,感興趣的可以了解下
    2024-11-11
  • Vue Router應(yīng)用方法詳解

    Vue Router應(yīng)用方法詳解

    在看這篇文章的幾點(diǎn)要求:需要你先知道Vue-Router是個(gè)什么東西,用來(lái)解決什么問題,以及它的基本使用。如果你還不懂的話,建議上官網(wǎng)了解下Vue-Router的基本使用后再回來(lái)看這篇文章
    2022-09-09
  • Vue.js項(xiàng)目模板搭建圖文教程

    Vue.js項(xiàng)目模板搭建圖文教程

    下面小編就為大家?guī)?lái)一篇Vue.js項(xiàng)目模板搭建圖文教程。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • AntV F2和vue-cli構(gòu)建移動(dòng)端可視化視圖過(guò)程詳解

    AntV F2和vue-cli構(gòu)建移動(dòng)端可視化視圖過(guò)程詳解

    這篇文章主要介紹了AntV F2和vue-cli構(gòu)建移動(dòng)端可視化視圖過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • element-ui多文件上傳的實(shí)現(xiàn)示例

    element-ui多文件上傳的實(shí)現(xiàn)示例

    這篇文章主要介紹了element-ui多文件上傳的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Vue表單控件數(shù)據(jù)綁定方法詳解

    Vue表單控件數(shù)據(jù)綁定方法詳解

    本文將詳細(xì)介紹Vue表單控件數(shù)據(jù)綁定方法,需要的朋友可以參考下
    2020-02-02
  • 將vue+nodejs項(xiàng)目部署到服務(wù)器上的實(shí)現(xiàn)

    將vue+nodejs項(xiàng)目部署到服務(wù)器上的實(shí)現(xiàn)

    本文主要介紹了將vue+nodejs項(xiàng)目部署到服務(wù)器上的實(shí)現(xiàn),使用Express生成器部署和前端Vue項(xiàng)目部署,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-03-03
  • vue實(shí)現(xiàn)在線進(jìn)制轉(zhuǎn)換功能

    vue實(shí)現(xiàn)在線進(jìn)制轉(zhuǎn)換功能

    這篇文章主要介紹了vue實(shí)現(xiàn)在線進(jìn)制轉(zhuǎn)換功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-04-04

最新評(píng)論