Electron Forge【實戰】桌面應用 —— AI聊天(下)

此為系列教程,需先完成

  • Electron Forge【實戰】桌面應用 —— AI聊天(上)
  • Electron Forge【實戰】桌面應用 —— AI聊天(中)

會話列表按更新時間倒序加載

在這里插入圖片描述
src/db.ts

db.version(1).stores({// 主鍵為id,且自增// 新增updatedAt字段,用于排序conversations: "++id, updatedAt",
});

src/stores/conversation.ts

    // 從本地存儲中查詢出會話列表async fetchConversations() {const items = await db.conversations.orderBy('updatedAt') // 按更新日期排序.reverse() // 倒序排列.toArray(); // 轉換為數組this.items = items;},

新創建的會話,在會話列表頂部

src/stores/conversation

      //   pinia 中新增會話this.items.unshift({id: newCId,...createdData,});

會話更新時,同步存儲到本地

src/views/Conversation.vue

      // 本次回答結束后if (data.is_end) {// 清空流式消息的內容streamContent = "";// 更新會話時,需要移除 id 字段,否則會報錯let temp_convsersation = JSON.parse(JSON.stringify(convsersation.value));delete temp_convsersation.id;await conversationStore.updateConversation(convsersation.value!.id,temp_convsersation);}

src/stores/conversation.ts

    async updateConversation(id: number, newData: Omit<ConversationProps, "id">) {// 本地存儲中更新會話await db.conversations.update(id, newData);//   pinia 中更新會話const index = this.items.findIndex((item) => item.id === id);if (index > -1) {this.items[index] = { id, ...newData };}},

聊天區自動滾動到底部

src/components/MessageList.vue
需對外暴露 ref

<div class="message-list" ref="_ref">
const _ref = ref<HTMLDivElement>();defineExpose({ref: _ref,
});

src/views/Conversation.vue

<MessageList :messages="convsersation!.msgList" ref="messageListRef" />
const messageListRef = ref<{ ref: HTMLDivElement }>();const messageScrollToBottom = async (behavior?: string) => {await nextTick();if (messageListRef.value) {// 獲取到自定義組件內的真實 ref 調用 scrollIntoView messageListRef.value.ref.scrollIntoView({block: "end",behavior: behavior as ScrollBehavior, // "auto" | "instant" | "smooth"});}
};

會話頁初次加載時

在 onMounted 末尾添加

await messageScrollToBottom();

切換當前會話時

在這里插入圖片描述

watch(() => route.params.id,async (newId: string) => {conversationId.value = parseInt(newId);// 切換當前會話時,聊天區自動滾動到底部await messageScrollToBottom();}
);

AI 流式回答問題時

onUpdateMessage 內

      // 根據消息id, 獲取到 loading 狀態的消息let msg = convsersation.value!.msgList[messageId];// 將 AI 回答的流式消息替換掉 loading 狀態的消息msg.content = streamContent;// 根據 AI 的返回,更新消息的狀態msg.status = getMessageStatus(data);// 用 dayjs 得到格式化的當前時間字符串msg.updatedAt = dayjs().format("YYYY-MM-DD HH:mm:ss");// 順滑滾動到底部await messageScrollToBottom("smooth");

滾動性能優化 – 僅當 AI 回答超過一行時才觸發滾動

let currentMessageListHeight = 0;
const checkAndScrollToBottom = async () => {if (messageListRef.value) {const newHeight = messageListRef.value.ref.clientHeight;if (newHeight > currentMessageListHeight) {currentMessageListHeight = newHeight;await messageScrollToBottom("smooth");}}
};

onUpdateMessage 內改為

      // 順滑滾動到底部await nextTick()await checkAndScrollToBottom()

切換會話時記得重置 currentMessageListHeight

watch(() => route.params.id,async (newId: string) => {conversationId.value = parseInt(newId);// 切換當前會話時,聊天區自動滾動到底部await messageScrollToBottom();// 切換當前會話時,將當前會話的消息列表的高度重置為0currentMessageListHeight = 0;}
);

恢復默認樣式

Tailwind CSS 默認移除了幾乎所有的默認樣式,導致無法渲染帶格式的富文本,通過插件 @tailwindcss/typography 來重置一套比較合理的默認樣式

npm install -D @tailwindcss/typography

src/index.css 中添加

@plugin "@tailwindcss/typography";

給目標內容加上類名 prose 即可

<div class="prose">要恢復樣式的內容</div>

自定義默認樣式

// 給 p 標簽添加 my-1 的 Tailwind CSS 樣式
prose-p:my-1

更多自定義樣式的方法見
https://github.com/tailwindlabs/tailwindcss-typography?tab=readme-ov-file#element-modifiers

渲染 markdown 的內容(支持代碼高亮)

AI 模型返回的都是 markdown 語法的文本,需要按 markdown 進行格式化渲染

npm install vue-markdown-render markdown-it-highlightjs --save

src/components/MessageList.vue 中使用

import VueMarkdown from "vue-markdown-render";
import markdownItHighlightjs from "markdown-it-highlightjs";const plugins = [markdownItHighlightjs];

要渲染的內容,改用 vue-markdown 組件,通過 source 傳入

            <divv-elseclass="prose prose-slate prose-hr:my-0 prose-li:my-0 prose-ul:my-3 prose-p:my-1 prose-pre:p-0"><vue-markdown :source="message.content" :plugins="plugins" /></div>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903072.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903072.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903072.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[架構之美]Ubuntu源碼部署APISIX全流程詳解(含避坑指南)

[架構之美]Ubuntu源碼部署APISIX全流程詳解(含避坑指南) 一、離線安裝場景需求分析 1.1 典型應用場景 金融/政務內網環境生產環境安全合規要求邊緣計算節點部署1.2 離線安裝難點 #mermaid-svg-B25djI0XquaOb1HM {font-family:"trebuchet ms",verdana,arial,sans-s…

多頭注意力(Multi?Head Attention)

1. 多頭注意力&#xff08;Multi?Head Attention&#xff09;原理 設輸入序列表示為矩陣 X ∈ R B L d model X\in\mathbb{R}^{B\times L\times d_{\text{model}}} X∈RBLdmodel?&#xff0c;其中 B B B&#xff1a;批大小&#xff08;batch size&#xff09;&#xff0c…

系列位置效應——AI與思維模型【80】

一、定義 系列位置效應思維模型是指在一系列事物或信息的呈現過程中&#xff0c;人們對于處于系列開頭和結尾部分的項目的記憶效果優于中間部分項目的現象。具體而言&#xff0c;開頭部分的記憶優勢被稱為首因效應&#xff0c;結尾部分的記憶優勢被稱為近因效應。這種效應反映…

MyBatis XML 配置完整示例(含所有核心配置項)

MyBatis XML 配置完整示例&#xff08;含所有核心配置項&#xff09; 1. 完整 mybatis-config.xml 配置文件 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""htt…

電商數據中臺架構:淘寶 API 實時采集與多源數據融合技術拆解

引言 在當今競爭激烈的電商領域&#xff0c;數據已成為企業決策和業務發展的核心驅動力。電商數據中臺能夠整合和管理企業內外部的各種數據&#xff0c;為業務提供有力支持。其中&#xff0c;淘寶 API 實時采集與多源數據融合技術是數據中臺架構中的關鍵部分。本文將深入探討這…

ubuntu22.04部署Snipe-IT

文章目錄 參考鏈接一、寫在前二、安裝操作系統三、安裝 PHP四、下載 Snipe-IT五、安裝依賴六、安裝數據庫并創建用戶七、安裝 Snipe-IT八、安裝 Nginx九、Web 繼續安裝 Snipe-IT補充&#xff1a;20250427補充&#xff1a; 最后 參考鏈接 How to Install Snipe-IT on Ubuntu 22…

圖論---Bellman-Ford算法

適用場景&#xff1a;有邊數限制 ->&#xff08;有負環也就沒影響了&#xff09;&#xff0c;存在負權邊&#xff0c;O( n * m )&#xff1b; 有負權回路時有的點距離會是負無窮&#xff0c;因此最短路存在的話就說明沒有負權回路。 從1號點經過不超過k條邊到每個點的距離…

A. Ideal Generator

time limit per test 1 second memory limit per test 256 megabytes We call an array aa, consisting of kk positive integers, palindromic if [a1,a2,…,ak][ak,ak?1,…,a1][a1,a2,…,ak][ak,ak?1,…,a1]. For example, the arrays [1,2,1][1,2,1] and [5,1,1,5][5,…

[詳細無套路]MDI Jade6.5安裝包下載安裝教程

目錄 1. 軟件包獲取 2. 下載安裝 3. 啟動 4. 問題記錄 寫在前面: 垂死病中驚坐起,JAVA博主居然開始更博客了~ 最近忙項目了, 沒啥更新的動力,見諒~見諒~. 這次博主的化工友友突然讓幫安裝JADE6.5軟件,本來以為不就一個軟件,直接拿捏. 不料竟然翻了個小車, 反被拿捏了. 既…

Serverless 在云原生后端的實踐與演化:從函數到平臺的革新

??個人主頁??:慌ZHANG-CSDN博客 ????期待您的關注 ???? 一、引言:從服務器到“無服務器”的后端演變 在傳統后端開發中,我們需要為服務配置并維護服務器資源,無論是物理機、虛擬機還是容器化服務,都需要: 管理系統運行環境 監控負載與擴縮容 保證高可用與安…

【專題三】二分查找(2)

&#x1f4dd;前言說明&#xff1a; 本專欄主要記錄本人的基礎算法學習以及LeetCode刷題記錄&#xff0c;按專題劃分每題主要記錄&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代碼&#xff1b;&#xff08;2&#xff09;優質解法 優質代碼&#xff1b;&#xff…

MySQL 詳解之函數:數據處理與計算的利器

在 MySQL 中,函數可以接受零個或多個輸入參數,并返回一個值。這些函數可以在 SELECT 語句的字段列表、WHERE 子句、HAVING 子句、ORDER BY 子句以及 UPDATE 和 INSERT 語句中使用。合理利用函數,可以簡化 SQL 語句,提高開發效率。 MySQL 提供了大量的內置函數 (Built-in F…

探索具身智能協作機器人:技術、應用與未來

具身智能協作機器人&#xff1a;概念與特點 具身智能協作機器人&#xff0c;簡單來說&#xff0c;就是將人工智能技術與機器人實體相結合&#xff0c;使其能夠在與人類共享的空間中進行安全、高效協作的智能設備。它打破了傳統機器人只能在預設環境中執行固定任務的局限&#…

基于物聯網的園林防火監測系統

標題:基于物聯網的園林防火監測系統 內容:1.摘要 隨著全球氣候變化和人類活動影響&#xff0c;園林火災發生頻率呈上升趨勢&#xff0c;給生態環境和人類生命財產造成巨大損失。為有效預防和應對園林火災&#xff0c;本文提出基于物聯網的園林防火監測系統。該系統綜合運用傳感…

JAVA多線程(8.0)

目錄 線程池 為什么使用線程池 線程池的使用 工廠類Executors&#xff08;工廠模式&#xff09; submit 實現一個線程池 線程池 為什么使用線程池 在前面我們都是通過new Thread() 來創建線程的&#xff0c;雖然在java中對線程的創建、中斷、銷毀、等值等功能提供了支持…

用go從零構建寫一個RPC(仿gRPC,tRPC)--- 版本1

希望借助手寫這個go的中間件項目&#xff0c;能夠理解go語言的特性以及用go寫中間件的優勢之處&#xff0c;同時也是為了更好的使用和優化公司用到的trpc&#xff0c;并且作者之前也使用過grpc并有一定的興趣&#xff0c;所以打算從0構建一個rpc系統&#xff0c;對于生產環境已…

【學習筆記】Stata

一、Stata簡介 Stata 是一種用于數據分析、數據管理和圖形生成的統計軟件包&#xff0c;廣泛應用于經濟學、社會學、政治科學等社會科學領域。 二、Stata基礎語法 2.1 數據管理 Stata 支持多種數據格式的導入&#xff0c;包括 Excel、CSV、文本文件等。 從 Excel 文件導入…

Redis數據結構SDS,IntSet,Dict

目錄 1.字符串&#xff1a;SDS 1.1.為什么叫做動態字符串 2.IntSet 2.1.inset如何保存大于當前編碼的最大數字&#xff1f; 3.Dict 3.1Dict的擴容 3.2Dict的收縮 3.3.rehash 1.字符串&#xff1a;SDS SDS的底層是C語言編寫的構建的一種簡單動態字符串 簡稱SDS&#xff…

Maven的聚合工程與繼承

目錄 一、為什么需要使用Maven工程 二、聚合工程的結構 三、聚合工程實現步驟 四、父工程統一管理版本 五、編譯打包 大家好&#xff0c;我是jstart千語。想著平時開發項目似乎都是用maven來管理的&#xff0c;并且大多都是聚合工程。而且在maven的聚合工程中&#xff0c…

前端職業發展:如何規劃前端工程師的成長路徑?

前端職業發展:如何規劃前端工程師的成長路徑? 大家好,我是全棧老李。今天咱們聊聊前端工程師的職業發展路徑,這個話題看似簡單,實則暗藏玄機。就像打游戲升級一樣,你得知道下一關是什么,才能提前準備裝備和技能點。 前端之路 一般我們從一個新手到大神,普遍需要經過…