前端AI對話功能實現攻略

一、對話內容渲染

在前端頁面的 AI 對話場景中,對話內容的渲染效果直接影響用戶的閱讀體驗和交互效率。合理選擇對話格式、優化流式對話呈現、嵌入自定義內容以及實現語音播報等功能,是提升整體體驗的關鍵。

對話格式選擇

MarkDown
  • 作為一種輕量級標記語言,語法簡潔易懂,能快速實現文本的加粗、斜體、列表、鏈接等格式渲染。在 AI 對話中,若回復內容以文字為主,且需要簡單的排版區分(如強調重點信息、羅列步驟等),MarkDown 是不錯的選擇。通過輕量的前端插件支持即可實現渲染,對移動端 H5 的性能影響較小,適合追求輕量化的場景
渲染插件-常規選擇
  • 當對話內容包含更豐富的樣式,如復雜的表格、代碼塊、圖片混排等,常規的 MarkDown 可能無法滿足需求,此時可選擇專業的渲染插件。例如,markdown-it、showdown.js、react-markdown、vue-markdown等等,能靈活配置渲染規則,支持自定義標簽。這類插件兼容性較好,能適配多數移動瀏覽器,適合對對話樣式有一定要求的場景。
渲染插件-編輯能力
  • 若業務場景要求用戶能編輯 AI 生成的對話內容(如修改文本、調整格式后保存或分享),則需要選擇具備編輯能力的渲染插件。
    • TinyMCE是一款功能強大的富文本編輯器,支持實時預覽、格式刷、表格編輯等功能,且能與 AI 對話接口無縫集成,實現 “生成 - 編輯 - 提交” 的閉環。
    • CKEditor提供了豐富的插件生態,可根據需求擴展圖片上傳、代碼編輯等功能,適合對編輯體驗要求較高的場景。
    • lexical 是一個功能強大的JavaScript庫,專為構建富文本編輯器而設計。它采用獨特的架構,允許開發者以靈活的方式創建和定制文本編輯體驗。可以用于處理用戶輸入的文本,對其進行語法分析、語義理解預處理等操作,同時支持流暢的文本顯示與交互,為AI對話功能提供穩定且高效的文本處理基礎
擴展場景
  • 如何對ai回答的內容實現編輯功能?
  • 如何對ai回答中的片段實現再潤色功能?

流式對話

流式對話能讓 AI 的回復內容逐字或逐句呈現,減少用戶等待感,提升交互流暢度。實現流式對話一般使用 SSE(Server-Sent Events)與后端建立長連接,后端在生成內容的過程中持續向前端推送數據。前端接收到數據后,需實時更新對話界面。

一般有兩種方式可以發起SSE長連接請求

使用EventSource對象

EventSource是瀏覽器原生支持的 SSE API,使用簡單且兼容性良好。示例代碼如下:

const eventSource = new EventSource('/your-api-url');
eventSource.onmessage = function(event) {const data = JSON.parse(event.data);// 處理后端推送的數據,更新對話界面// ......
};
eventSource.onerror = function(error) {console.error('SSE連接錯誤:', error);eventSource.close();
};

使用EventSource時,默認會自動重連,適合對連接穩定性要求高的場景。但它僅支持 HTTP/HTTPS 協議,且無法自定義請求頭,以及傳遞復雜的請求參數。

使用fetch API 模擬 SSE

通過fetch發起 GET 請求,并手動處理響應流,可實現類似 SSE 的效果。此方式更靈活,能自定義請求方法、請求頭,但需要開發者自行處理連接管理和錯誤重連邏輯:

async function createSSEStream() {const response = await fetch('/your-api-url', {method: 'GET', // 也可以是Postheaders: {'Content-Type': 'text/event-stream',// 可添加自定義請求頭參數}});const reader = response.body.getReader();const decoder = new TextDecoder('utf-8');// while響應流式數據while (true) {const { done, value } = await reader.read();if (done) break;const text = decoder.decode(value, { stream: true });const lines = text.split('\n').filter(line => line.trim() !== '');for (const line of lines) {if (line.startsWith('data:')) {const data = JSON.parse(line.slice(5).trim());// 處理后端推送的數據,更新對話界面// ......}}}
}

使用fetch模擬 SSE 時,可根據業務需求靈活配置請求參數,例如添加身份驗證信息、調整請求超時時間等,適用于對請求定制化要求較高的復雜場景。

場景擴展
  • 如何中斷長連接

對話嵌入自定義內容-echarts

在 AI 對話中嵌入圖表(如數據可視化、趨勢分析圖)能讓信息更直觀易懂,ECharts 是實現這一功能的常用工具。

echarts提示詞
  • 前端需要向 AI 傳遞明確的提示信息,說明需要生成圖表的類型(如折線圖、柱狀圖)、數據維度(如時間、數值)、標題等內容。例如,提示詞可以是 “請根據用戶問題,返回圖表數據,x 軸為日期,y 軸為活躍人數,標題為‘xxxx表’,數據格式為echarts折線圖的option, 以JSON 格式輸出”。
渲染echarts
  • 一般將echarts提示詞調整穩定以后,需要結合你選擇的md渲染插件,定義一套規則來渲染echarts,推薦使用規則:```echart {option} ```,以下有兩個實踐中的實例
    • markdown-it(自定義代碼塊規則)
// <template>
// 	<div
// 		class="message-wrap"
// 		v-html="renderedContent"
// 	/>
// </template>
import { nextTick, ref, watchEffect } from 'vue'
import Markdown from 'markdown-it'
import type { Options } from 'markdown-it'
import highlight from 'highlight.js'
import * as echarts from 'echarts'const props = defineProps<Props>()
const renderedContent = ref('')const echartMap = ref(new Map())
const echartRendered = ref<string[]>([])
const mdOptions: Options = {linkify: true,typographer: true,breaks: true,langPrefix: 'language-',// 代碼高亮highlight(str, lang) {if (lang && highlight.getLanguage(lang)) {try {return '<pre class="hljs"><code>' + highlight.highlight(lang, str, true).value + '</code></pre>'} catch (__) {}}return ''},
}const md = new Markdown(mdOptions)
const defaultRender = md.renderer.rules.fence
md.renderer.rules.think = (tokens, idx) => {return `<div class="think-block">${md.utils.escapeHtml(tokens[idx].content)}</div>`
}
md.renderer.rules.fence = (tokens, idx, options, env, self) => {const token = tokens[idx]if (token.info.trim() === 'echart') {const chartId = `chart-${props?.id}-${idx}`try {if (!echartMap.value.has(chartId)) {const option = JSON.parse(token.content)console.log('解析圖表配置成功')echartMap.value.set(chartId, option)}return `<div id='${chartId}' style='width:calc(100vw - 12px * 2 - 16px * 2);height:calc((100vw - 12px * 2 - 16px * 2) * 0.8)'></div>`} catch (error) {console.error('解析圖表配置失敗', token.content, error)return `<div id='${chartId}' class='chart-loading' style='width:calc(100vw - 12px * 2 - 16px * 2);height:calc((100vw - 12px * 2 - 16px * 2) * 0.8)' >圖表加載中...</div>`}}return defaultRender(tokens, idx, options, env, self)
}// 添加think標簽渲染規則watchEffect(() => {renderedContent.value = md.render(props?.content)nextTick(() => {// 等待 DOM 更新后初始化圖表echartMap.value.forEach((option, id) => {const container = document.getElementById(id)const width = container?.getBoundingClientRect().widthif (!container) {return}const chart = echarts.init(container, '', {height: width * 0.8,devicePixelRatio: 2,})echartRendered.value.push(id)chart.setOption({ ...option, animation: false, animationDurationUpdate: 0 })})})
})
  • react-markdown自定義代碼塊規則
const MarkdownContent = () => {const resize = useRef();const [resizeMap, setResizeMap] = useState([]); // 多圖表尺寸動態優化useEffect(() => {if (!resize.current) {resize.current = () => {resizeMap.forEach((resize) => resize());};window.addEventListener('resize', resize.current);}return () => {if (resize.current) {window.removeEventListener('resize', resize.current);resize.current = null;}};}, [resizeMap]);const [renderMap, setRenderMap] = useState({}); // 解決圖表頻繁閃動、以及只有第一個圖表生效的問題useEffect(() => {const map = [];Object.keys(renderMap).forEach((echartId) => {const item = renderMap[echartId];if (!item.rendered) {const echart = echarts.init(item.dom, '', {devicePixelRatio: 2,height: 300,width,});echart.setOption(item.option);item.rendered = true;map.push(echart.resize);}});setResizeMap([...resizeMap, ...map]);}, [renderMap]);const createEchartDom = (echartId, option) => {const dom = document.createElement('div');dom.id = echartId;dom.style.width = '100%';dom.style.maxWidth = '100%';dom.style.height = '300px';// 解決圖表頻繁閃動、以及只有第一個圖表生效的問題setRenderMap({...renderMap,[echartId]: {dom,option,rendered: false,},});return dom;};const codeRender = (props: any) => {const { children, className, ...rest } = props;const match = /language-(\w+)/.exec(className || '');if (match && match[1] === 'echart') {try {const startLine = props.node.position.start.line;const echartId = `${id}-${startLine}`;const option = {...JSON.parse(children),animation: false,animationDurationUpdate: 0,};let domif (!renderMap[echartId]) {dom = createEchartDom(echartId, option);} else {dom = renderMap[echartId].dom}return (<divstyle={{width: '100%',height: `${300}px`,}}ref={(node) => node?.appendChild(dom)}/>);} catch {return (// 圖表規則解析失敗<divstyle={{width: '100%',height: `${300}px`,display: 'flex',justifyContent: 'center',alignItems: 'center',border: '1px solid #dcdfe6',borderRadius: 8,background: '#f5f7fa',}}>圖表加載中...</div>);}}return  <code {...rest} className={className}>{children}</code>};return (<Markdowncomponents={{code: (props: any) => codeRender(props, width),}}>{content}</Markdown>);
};
流式圖表渲染
  • 上面兩步實現了在ai對話中實現圖表渲染的能力,但是通常情況下對話過程是流式,會出現以下幾個問題:
    • 圖表規則解析失敗:通常發生在 option 處于正在生成中的情況下,解決辦法就是加一個圖表加載樣式
    • 圖表會頻繁閃動:通常發送在 option 已經生成完成,但是回答仍然在生成中的情況下,原因markdown渲染插件會生成新的echart容器,頻繁卸載掛載dom元素,解決辦法將已經生成好的option 和其綁定的圖表容器緩存起來,每次markdown渲染復用圖表容器
    • 只有第一個圖表生效:通常發送在一個會話或一個回答中出現多個圖表的情況下,解決辦法就是配合生成獨立的id,并配合緩存渲染圖表
場景擴展
  • 如何實現ai回答中的渲染思考內容?

語音播報

語音播報能讓用戶在不便查看屏幕時獲取對話內容,提升使用場景的靈活性。

長文本低延遲播報優化
  • 對于長文本的語音播報,需解決延遲和卡頓問題。可采用分段播報策略,將長文本按標點符號或固定長度分割成多個片段,并發加載文本的語音數據,同時使用 audio 逐段播報,減少等待時間。另外,可根據網絡狀況動態調整分段長度,在網絡較差時減小片段長度,避免因數據傳輸延遲導致播報中斷。還可以通過緩存已播報過的文本語音,當用戶重復收聽時直接調用緩存,提升響應速度
  • 參考方法:
/** 語音播放 */
export const useSpeech = content => {const audioDom = document.createElement('audio')const audioRef = useRef(audioDom)const { read } = useSpeechWithSse() // read為文本轉音頻請求方法 返回promiseconst [isPlaying, setIsPlaying] = useState(false)const [playEnded, setPlayEnded] = useState(true)const [isLoading, setIsLoading] = useState(false)const [reedList, setReedList] = useState([])const [readIndex, setReadIndex] = useState(0)const pause = useCallback(() => {if (audioRef.current) {audioRef.current.pause()setIsPlaying(false)setPlayEnded(true)setIsLoading(false)setReedList([])}}, [])const speech = useCallback(async () => {setReadIndex(0)try {setIsLoading(true)// 分割成多個片段let strIndex = 0let curText = ''let textlist = []while (strIndex < content.length) {curText = `${curText}${content[strIndex]}`if ([',', '。', ';', '?', ',', '!'].includes(content[strIndex]) ||curText.endsWith('\n')) {const formatedText = curText.replace(/[\n#*-]+/g, '').trim()if (formatedText) {textlist.push(formatedText)curText = ''}}strIndex++}if (curText) {textlist.push(curText)curText = ''}strIndex = 0setIsPlaying(true)// 對文本片段的請求并發做出限制,500毫秒添加一個請求const tempReedList = []const timer = setInterval(() => {if (textlist.length === 0) {clearInterval(timer)} else {const nextText = textlist.shift()tempReedList.push(read({ text: nextText }))setReedList(tempReedList)}}, 500)} catch (error) {console.error('播放失敗:', error)} finally {// setIsLoading(false);}}, [read, content, setIsLoading, audioRef])const handleRead = useCallback(() => {if (isPlaying) {pause()} else {speech()}}, [isPlaying, speech, pause])// 監聽reedList 依次播報語音片段useEffect(() => {const loadRead = async () => {if (playEnded && isPlaying && reedList.length > readIndex) {setPlayEnded(false)const curReadUrl = await reedList[readIndex]setReadIndex(readIndex + 1)if (curReadUrl && audioRef.current) {audioRef.current.src = curReadUrlsetIsLoading(false)}}if (reedList.length > 0 && reedList.length === readIndex) {setPlayEnded(true)setIsPlaying(false)setReadIndex(0)setReedList([])}}loadRead()}, [playEnded, isPlaying, reedList])useEffect(() => {// 處理音頻播放結束const handleEnded = () => {setPlayEnded(true)}const handleOnload = () => {setPlayEnded(false)audioRef.current?.play()}// 處理音頻播放錯誤const handleError = e => {console.error('音頻播放錯誤:', e)setPlayEnded(true)setIsPlaying(false)setIsLoading(false)}const audio = audioRef.currentif (audio) {audio.addEventListener('ended', handleEnded)audio.addEventListener('error', handleError)audio.addEventListener('loadeddata', handleOnload)}return () => {if (audio) {audio.removeEventListener('ended', handleEnded)audio.removeEventListener('error', handleError)audio.removeEventListener('loadeddata', handleOnload)URL.revokeObjectURL(audio.src)}}}, [])return { handleRead, isPlaying, isLoading }
}
場景擴展
  1. 如何實現回答邊生成邊播報語音?

二、對話輸入框

對話輸入框作為用戶與 AI 交互的核心入口,在移動端 H5
頁面設計中需兼顧便捷性高效性。從交互設計角度,通過語音輸入與文字輸入雙模式,降低用戶輸入成本,提升交互效率。在視覺層面,可以將輸入的部分文本定制化樣式功能,例如提供預設選項,優化用戶輸入體驗。

富文本格式輸入

集成富文本編輯器,支持用戶輸入加粗、斜體、列表、鏈接等多樣化格式內容。在 AI 對話場景中,用戶可通過富文本輸入詳細描述需求,AI 根據格式化后的文本進行更精準的理解與回復,提升交互效率。

  • 以下是通過lexical 富文本插件實現的效果:

具有定制樣式、交互功能的文本

在ai對話中,輸入框內支持預設的問題模板(定制的文本節點樣式與交互)是提升用戶輸入體驗的關鍵。

  • 以下是通過lexical 富文本插件實現的效果:

隱藏提示詞

高程度定制化的ai對話應用,往往需要給用戶輸入問題補充提示詞,同時要避免提示詞干擾用戶體驗,所以需要隱藏提示詞

  1. 可以將提示詞以 CSS 樣式方式隱藏;
  2. 也可以在用戶觸發對話時,通過 JavaScript 動態將提示詞注入拼接;

語音識別

語音識別功能極大提升了 H5 頁面的交互便捷性,尤其契合移動端用戶碎片化、多場景的使用需求。在復雜的移動網絡環境與多變的用戶輸入場景下,通過多重技術優化實現高效交互

快速識別
  • 借助高性能語音識別 API,實現毫秒級響應。通過優化網絡請求與數據處理流程,減少語音數據上傳、識別及結果返回的耗時,讓用戶感受 “即說即現” 的流暢體驗。
場景擴展
  • 如何做到逐字、詞識別?

停止生成

在 AI 生成內容的過程中,當用戶發現 AI 輸出內容與預期不符、生成方向偏離主題,或臨時調整創作思路時,可通過點擊 “停止生成” 按鈕。點中斷AI 生成進程,避免無效內容的持續輸出。同時,系統會保留已生成的內容片段,用戶可基于此進行修改、補充或重新發起生成指令,實現高效且個性化的內容創作體驗。

eventSource (sse) 停止鏈接
  • 可以通過調用 EventSource 實例的close()方法來停止與服務器的連接,不再接收新的事件流數據。
const eventSource = new EventSource('your_sse_url')
// 需要停止鏈接時執行
eventSource.close()
// 果希望在關閉后進行一些清理操作,可以通過監聽close事件實現
eventSource.addEventListener('close', function() { console.log('SSE connection closed'); })
fetch (sse) 停止鏈接
  • 使用<font style="color:rgb(0, 0, 0);">fetch</font>模擬 SSE 時,通常是通過不斷輪詢獲取數據來模擬流式傳輸。要停止鏈接,在<font style="color:rgb(0, 0, 0);">fetch</font>請求中傳入<font style="color:rgb(0, 0, 0);">signal</font>參數來終止請求
const controller = new AbortController(); 
const signal = controller.signal; 
fetch('your_url', { signal }).then(response => response.text()).then(data => console.log(data))
// 需要停止時調用,  請求將被立即終止,并拋出AbortError異常
controller.abort()
場景擴展
  • 如何重新生成回答?

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

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

相關文章

深入理解Redis持久化:讓你的數據永不丟失

1 Redis持久化概述 1.1 什么是Redis持久化 Redis作為一個高性能的內存數據庫,默認情況下數據存儲在內存中,這意味著一旦服務器重啟或發生故障,內存中的數據將會丟失。為了保證數據的持久性和可靠性,Redis提供了持久化機制,將內存中的數據保存到磁盤中。 持久化是Redis實…

IC驗證 AHB-RAM 項目(二)——接口與事務代碼的編寫

目錄準備工作接口相關代碼編寫事務相關代碼編寫準備工作 DVT&#xff08;Design and Verification Tools&#xff09;是一款專門為 IC 驗證打造的 IDE 插件&#xff0c;可以理解為智能的 Verilog/System Verilog 編輯器&#xff0c;在 VS Code、Eclipse 軟件中使用。 接口相關…

基于Spring Boot的智能民宿預訂與游玩系統設計與實現 民宿管理系統 民宿預訂系統 民宿訂房系統

&#x1f525;作者&#xff1a;it畢設實戰小研&#x1f525; &#x1f496;簡介&#xff1a;java、微信小程序、安卓&#xff1b;定制開發&#xff0c;遠程調試 代碼講解&#xff0c;文檔指導&#xff0c;ppt制作&#x1f496; 精彩專欄推薦訂閱&#xff1a;在下方專欄&#x1…

大模型的底層運算線性代數

深度學習的本質是用數學語言描述并處理真實世界中的信息&#xff0c;而線性代數正是這門語言的基石。它不僅提供了高效的數值計算工具&#xff0c;更在根本上定義了如何以可計算、可組合、可度量的方式表示和變換數據。 1 如何描述世界&#x1f4ca; 真實世界的數據&#xff08…

Rust 中 i32 與 *i32 的深度解析

Rust 中 &i32 與 *i32 的深度解析 在 Rust 中&#xff0c;&i32 和 *i32 是兩種完全不同的指針類型&#xff0c;它們在安全性、所有權和使用方式上有本質區別。以下是詳細對比&#xff1a; 核心區別概覽 #mermaid-svg-rCa8lLmHB7MK9P6K {font-family:"trebuchet ms…

【PyTorch項目實戰】OpenNMT本地機器翻譯框架 —— 支持本地部署和自定義訓練

文章目錄一、OpenNMT&#xff08;Neural Machine Translation&#xff0c;NMT&#xff09;1. 概述2. 核心特性3. 系統架構4. 與其他翻譯工具的區別二、基于 OpenNMT-py 的機器翻譯框架1. 環境配置&#xff08;以OpenNMT-py版本為例&#xff09;&#xff08;1&#xff09;pip安裝…

基于prompt的生物信息學:多組學分析的新界面

以前總以為綜述/評論是假大空&#xff0c;最近在朋友的影響下才發現&#xff0c;大佬的綜述/評論內容的確很值得一讀&#xff0c;也值得分享的。比如這篇講我比較感興趣的AI輔助生信分析的&#xff0c;相信大家都是已經實踐中用上了&#xff0c;看看大佬的評論&#xff0c;拓寬…

Nacos-8--分析一下nacos中的AP和CP模式

Nacos支持兩種模式來滿足不同場景下的需求&#xff1a;AP模式&#xff08;強調可用性&#xff09;和CP模式&#xff08;強調一致性&#xff09;。 這兩種模式的選擇主要基于CAP理論&#xff0c;該理論指出在一個分布式系統中&#xff0c;無法同時保證一致性&#xff08;Consist…

水閘安全監測的主要核心內容

水閘安全監測是指通過一系列技術手段和管理措施&#xff0c;對水閘的結構狀態、運行性能及環境條件進行實時或定期的觀測與評估&#xff0c;以確保水閘在設計壽命期內的安全性和可靠性。其核心目標是及時發現潛在的安全隱患&#xff0c;防止事故發生&#xff0c;保障水利工程的…

嵌入式系統學習Day19(數據結構)

數據結構的概念&#xff1a; 相互之間存在一種或多種特定關系的數據元素的集合。數據之間關系&#xff1a;邏輯關系&#xff1a;集合&#xff0c;線性&#xff08;1對1&#xff0c;中間位置的值有且僅有一個前驅&#xff0c;一個后繼&#xff09;&#xff0c;樹&#xff08;1對…

Pandas中數據清理、連接數據以及合并多個數據集的方法

一、簡介1.數據清理的重要性&#xff1a;在進行數據分析前&#xff0c;需進行數據清理&#xff0c;使每個觀測值成一行、每個變量成一列、每種觀測單元構成一張表格。2.數據組合的必要性&#xff1a;數據整理好后&#xff0c;可能需要將多張表格組合才能進行某些分析&#xff0…

JavaSSM框架從入門到精通!第二天(MyBatis(一))!

一、 Mybatis 框架1. Mybatis 框架簡介Mybatis 是 apache 的一個開源項目&#xff0c;名叫 iBatis &#xff0c;2010 年這個項目由 apache 遷移到了 google&#xff0c;并命名為 Mybatis&#xff0c;2013 年遷移到了 GitHub&#xff0c;可以在 GitHub 下載源碼。2. Mybatis 的下…

Linux下Mysql命令,創建mysql,刪除mysql

在 Linux 系統下&#xff0c;您可以通過命令行來創建和刪除 MySQL 數據庫。以下是詳細的操作步驟&#xff0c;包括創建和刪除數據庫、用戶&#xff0c;以及常見的相關管理命令。1. 登錄 MySQL在執行任何 MySQL 操作之前&#xff0c;需要先登錄 MySQL。1.1 使用 root 用戶登錄 M…

假設檢驗的原理

假設檢驗是統計學中用于判斷樣本數據是否支持某個特定假設的方法。其核心思想是通過樣本數據對總體參數或分布提出假設&#xff0c;并利用統計量來判斷這些假設的合理性。假設檢驗的基本步驟如下&#xff1a;1. 假設&#xff08;Hypothesis&#xff09;在統計學中&#xff0c;假…

信號、內存共享等實現

信號&#xff08;signal&#xff09;#include <signal.h> #include <stdio.h> #include <unistd.h>void handler(int sig) {printf("收到信號: %d\n", sig); }int main() {signal(SIGUSR1, handler); // 注冊用戶自定義信號printf("進程 PI…

《從日常到前沿:AI 在教育、醫療、制造業的真實落地案例》文章提綱

引言&#xff1a;AI 落地的多元圖景?簡述 AI 從實驗室走向實際應用的發展趨勢?說明選擇教育、醫療、制造業的原因 —— 覆蓋民生與基礎產業&#xff0c;落地場景具有代表性?AI 在教育領域的落地案例?個性化學習&#xff1a;如某在線教育平臺利用 AI 分析學生學習數據&#…

決策樹(1)

一、樹模型與決策樹基礎決策樹概念&#xff1a;從根節點開始一步步走到葉子節點得出決策&#xff0c;所有數據最終都會落到葉子節點&#xff0c;既可用于分類&#xff0c;也可用于回歸。樹的組成根節點&#xff1a;第一個選擇點。非葉子節點與分支&#xff1a;中間決策過程。葉…

電視系統:開啟視聽新時代

在當今數字化浪潮席卷的時代&#xff0c;電視領域正經歷著一場深刻的變革&#xff0c;而電視系統無疑是這場變革中的耀眼明星。簡單來講&#xff0c;電視系統就是互聯網協議電視&#xff0c;它宛如一座橋梁&#xff0c;巧妙地利用寬帶有線電視網&#xff0c;將多媒體、互聯網、…

字節開源了一款具備長期記憶能力的多模態智能體:M3-Agent

貓頭虎AI分享&#xff5c;字節開源了一款具備長期記憶能力的多模態智能體&#xff1a;M3-Agent 近年來&#xff0c;多模態大模型的發展迅猛&#xff0c;但如何賦予智能體類似人類的長期記憶能力&#xff0c;一直是研究中的核心挑戰。字節跳動開源的 M3-Agent&#xff0c;正是面…

第十六屆藍橋杯青少組C++省賽[2025.8.10]第二部分編程題(6、魔術撲克牌排列)

參考程序&#xff1a;#include<bits/stdc.h> using namespace std; long long dp[105]; long long c(int n) {dp[0] 1;for(int i1; i< n; i){for(int j0; j<i; j){dp[i] dp[j] * dp[i -1-j];}}return dp[n]; } int main() {int n;cin >> n;cout <<c(n…