ByteMD 插件系統詳解

ByteMD 插件系統詳解

在這里插入圖片描述
在這里插入圖片描述

ByteMD 的插件系統是其強大擴展性的核心。它允許開發者在 Markdown 解析、AST 轉換、HTML 渲染、以及編輯器 UI 交互的各個階段注入自定義邏輯。這得益于 ByteMD 深度集成了 unified 處理器和其豐富的生態系統(remark 用于 Markdown,rehype 用于 HTML)。

1. 插件的本質

一個 ByteMD 插件是一個返回 BytemdPlugin 接口對象的函數。這個對象包含了多個可選的鉤子 (Hooks),每個鉤子都對應 ByteMD 內部處理流程的不同階段。

BytemdPlugin 接口的主要成員:

  • viewerEffect?(el: HTMLElement): BytemdViewerContext | void:

    • 時機: 當 Viewer 組件渲染完成并掛載到 DOM 后執行。
    • 參數: elViewer 的根 DOM 元素。
    • 用途: 適合用于對最終渲染的 HTML 內容進行 DOM 操作,例如添加事件監聽器、初始化第三方 JS 庫(如流程圖渲染庫)、或者對圖片進行懶加載處理等。
    • 返回值: 可以返回一個包含 destroy?: () => void 方法的對象,當 Viewer 卸載時,會調用 destroy 方法進行清理。
  • editorEffect?(editor: Editor): BytemdEditorContext | void:

    • 時機: 當 Editor 組件初始化完成(通常是 CodeMirror/ProseMirror 實例創建后)并掛載到 DOM 后執行。
    • 參數: editorCodeMirror 的實例(如果 ByteMD 內部使用 CodeMirror)。這個實例提供了對編輯器核心功能的直接訪問,例如獲取/設置內容、插入文本、注冊快捷鍵等。
    • 用途: 適合用于與編輯器本身進行低級別交互,例如自定義快捷鍵、實現圖片拖拽上傳、自定義粘貼行為、或者在編輯器內容變化時觸發額外邏輯。
    • 返回值: 同樣可以返回一個包含 destroy?: () => void 方法的對象,用于編輯器卸載時的清理。
  • remark?(processor: RemarkProcessor): RemarkProcessor:

    • 時機: 在 Markdown 文本被 remark-parse 解析為 MDAST (Markdown Abstract Syntax Tree) 之后,但在轉換為 HAST 之前。
    • 參數: processor 是一個 remark 處理器實例。
    • 用途: 這是處理 Markdown 語法的核心鉤子。你可以通過 processor.use() 方法來注冊自定義的 remark 插件。這些 remark 插件會遍歷并修改 MDAST,例如:
      • 添加對 GFM (GitHub Flavored Markdown) 的支持(表格、任務列表)。
      • 識別和處理自定義的 Markdown 語法(例如特殊的塊引用、自定義標簽)。
      • 在 AST 級別進行內容轉換或驗證。
  • rehype?(processor: RehypeProcessor): RehypeProcessor:

    • 時機: 在 MDAST 被 remark-rehype 轉換為 HAST (Hypertext Abstract Syntax Tree) 之后,但在轉換為最終 HTML 字符串之前。
    • 參數: processor 是一個 rehype 處理器實例。
    • 用途: 這是處理 HTML 語法的核心鉤子。你可以通過 processor.use() 方法來注冊自定義的 rehype 插件。這些 rehype 插件會遍歷并修改 HAST,例如:
      • 為圖片添加 loading="lazy" 屬性。
      • 處理代碼塊,添加行號或復制按鈕。
      • 將數學公式的 AST 節點渲染為 KaTeX 或 MathJax。
      • 在 HTML 級別進行內容轉換或優化。
  • actions?: BytemdAction[]:

    • 時機: 在編輯器工具欄渲染時。
    • 用途: 用于在 ByteMD 的工具欄中添加自定義按鈕。每個 BytemdAction 對象定義了按鈕的圖標、標題和點擊時的處理函數。這允許你為自定義功能提供用戶友好的界面。
  • i18n?: Record<string, string>:

    • 用途: 提供插件內部文本的國際化支持。
  • override?: Partial<BytemdLocale>:

    • 用途: 覆蓋 ByteMD 默認的國際化文本。
2. 插件的工作流
  1. 初始化: 當 BytemdEditorBytemdViewer 組件被實例化時,它會接收一個 plugins 數組。
  2. 鉤子注冊: ByteMD 核心會遍歷這個 plugins 數組,收集每個插件返回對象中的所有鉤子(remark, rehype, editorEffect, viewerEffect, actions 等)。
  3. Markdown 解析與 AST 轉換:
    • 當 Markdown 內容變化時,unified 處理器被激活。
    • 首先執行 remark-parse 將 Markdown 解析為 MDAST。
    • 然后,所有注冊的 remark 插件會依次處理 MDAST。
    • 接著,remark-rehype 將 MDAST 轉換為 HAST。
    • 之后,所有注冊的 rehype 插件會依次處理 HAST。
    • 最后,rehype-stringify 將 HAST 轉換為 HTML 字符串。
  4. UI 交互:
    • actions 鉤子定義的按鈕會被添加到工具欄,其 handler 在點擊時執行。
    • editorEffect 在編輯器初始化后執行,允許對 CodeMirror 實例進行操作。
    • viewerEffect 在預覽器渲染 HTML 后執行,允許對渲染結果的 DOM 進行操作。

自定義插件示例:添加一個“插入日期時間”按鈕和高亮特定文本

我們將創建一個自定義插件,實現兩個功能:

  1. 工具欄按鈕: 在工具欄添加一個“插入日期時間”按鈕,點擊后在光標處插入當前日期時間。
  2. 高亮特定關鍵詞: 自動將 Markdown 中出現的特定關鍵詞(例如“重要”、“注意”)在預覽時用 <mark> 標簽高亮顯示。
1. 創建插件文件 (bytemd-plugin-custom.ts)
// src/plugins/bytemd-plugin-custom.ts
import type { BytemdPlugin } from 'bytemd';
import type { RemarkPlugin } from 'unified';
import type { Node } from 'unist'; // MDAST/HAST 節點的通用類型
import { visit } from 'unist-util-visit'; // 遍歷 AST 的工具// 定義插件的選項(如果需要)
interface CustomPluginOptions {highlightKeywords?: string[];
}// Remark 插件:查找并標記需要高亮的文本
const remarkCustomHighlight: RemarkPlugin<[CustomPluginOptions?]> = (options) => {const keywords = options?.highlightKeywords || ['重要', '注意'];return (tree) => {visit(tree, 'text', (node: Node) => {// 確保是文本節點且有值if (typeof node.value === 'string') {let newValue = node.value;keywords.forEach(keyword => {// 使用正則表達式替換,以便處理多個出現和避免替換已經替換過的部分// 這里的替換比較簡單,如果涉及到復雜的嵌套或HTML實體,需要更復雜的AST操作newValue = newValue.replace(new RegExp(`(${keyword})`, 'g'),`==$1==` // CommonMark 規范中雙等號可以表示高亮(雖然不常用,但可以被rehype處理)// 或者自定義一個Markdown語法,例如 [[$1]],然后在rehype中處理);});node.value = newValue; // 更新節點值}});};
};// Rehype 插件:將特殊的 ==text== 標記轉換為 <mark> 標簽
// 這里我們需要處理 remark 階段插入的 ==...== 標記
// Bytemd 的 gfm 插件默認可能會處理 ==,如果沒有,則需要自定義rehype插件
// 實際上,更Robust的方式是remark插件創建自定義MDAST節點,然后rehype插件渲染它
const rehypeCustomHighlight: RemarkPlugin<[]> = () => (tree) => {visit(tree, { type: 'text' }, (node: Node) => {if (typeof node.value === 'string' && node.value.includes('==')) {// 匹配 ==text== 模式const parts = node.value.split(/(==[^=]+==)/g); // 分割字符串const newChildren = parts.flatMap(part => {if (part.startsWith('==') && part.endsWith('==')) {return {type: 'element',tagName: 'mark',properties: {},children: [{ type: 'text', value: part.slice(2, -2) }], // 移除 ==};}return { type: 'text', value: part };});// 替換當前文本節點為新的元素/文本節點數組// 這里需要更高級的unist-util-flatmap 或 unist-util-splice 等工具來替換節點// 簡單起見,這里直接修改當前節點的兄弟節點,但這不是標準做法// 在實際的unified插件中,通常是返回新的樹,或者替換當前節點// 為了演示方便,我們假設直接修改 text 節點的 value,并依賴rehype默認的HTML渲染// 但更嚴謹的自定義渲染,remark會創建custom node,rehype會識別并渲染// 由于bytemd-plugin-gfm包含了對 ==highlight== 的支持,這里可以直接利用// 如果bytemd默認不處理,我們需要構建一個真正的rehype插件來解析HTML文本// 假設 gfm 插件處理了 `==highlight==`,我們這里就不需要特殊的 rehype 轉換// 而是讓 remark 插件將文本轉換為類似 `==關鍵詞==` 的格式,讓 gfm 插件去渲染}});
};const bytemdPluginCustom = (options?: CustomPluginOptions): BytemdPlugin => {return {// 插件名稱,用于調試name: 'custom-plugin',// 工具欄動作actions: [{title: '插入日期時間',icon: '<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"></path></svg>', // 一個簡單的日期時間圖標 SVGhandler: {type: 'action',click({ editor, appendBlock }) {const now = new Date();const year = now.getFullYear();const month = (now.getMonth() + 1).toString().padStart(2, '0');const day = now.getDate().toString().padStart(2, '0');const hours = now.getHours().toString().padStart(2, '0');const minutes = now.getMinutes().toString().padStart(2, '0');const seconds = now.getSeconds().toString().padStart(2, '0');const dateTimeString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;editor.replaceSelection(dateTimeString); // 在光標處插入文本},},},],// Remark 插件:在 Markdown AST 階段處理remark: (processor) => processor.use(remarkCustomHighlight, options),// Rehype 插件:在 HTML AST 階段處理// 注意:如果 bytemd 的 plugin-gfm 已經支持 ==highlight==,這里就不需要額外的 rehype 插件了// 如果需要更復雜的自定義高亮,則可能需要編寫一個 `rehype` 插件來解析 `==` 或自定義語法// 為了簡化,我們假設 `plugin-gfm` 已經能把 `==text==` 渲染為 `<mark>`,// 所以這里的 rehypeCustomHighlight 暫時不啟用,或者只做調試用// rehype: (processor) => processor.use(rehypeCustomHighlight),};
};export default bytemdPluginCustom;

代碼解釋:

  • remarkCustomHighlight (Remark 插件):
    • 接收 options 來配置要高亮的關鍵詞。
    • 使用 unist-util-visit 遍歷 MDAST 中的所有 text 節點。
    • 對于每個文本節點,檢查是否包含任何關鍵詞。
    • 如果包含,就將關鍵詞用 ==...== 包裹起來。這是因為 ByteMD 的 plugin-gfm 默認支持 CommonMark 的 ==highlight== 語法,它會被渲染為 <mark> 標簽。這樣我們就直接利用了現有的渲染能力。
  • rehypeCustomHighlight (Rehype 插件 - 備用/調試):
    • 這里為了說明 rehype 插件的作用,提供了一個簡單的例子。
    • 它的作用是遍歷 HAST 中的文本節點,查找 ==...== 模式,并將其替換為 mark 元素。
    • 但在我們的例子中,如果 plugin-gfm 已經處理 ==highlight==,這個 rehype 插件就不是必須的。 實際應用中,rehype 插件更常用于添加額外的 HTML 屬性、修改已生成的 HTML 結構、或者處理一些 remark 階段無法處理的 HTML 特性。
  • bytemdPluginCustom (ByteMD 插件):
    • 返回一個 BytemdPlugin 接口的對象。
    • name: 插件的唯一標識。
    • actions: 定義了一個工具欄按鈕。
      • title: 按鈕的提示文本。
      • icon: 按鈕的 SVG 圖標。
      • handler: 點擊按鈕時執行的邏輯。editor.replaceSelection() 是 CodeMirror 提供的方法,用于在當前光標處插入或替換選中的文本。
    • remark: 注冊了我們自定義的 remarkCustomHighlight 插件,并傳遞了配置選項。
2. 在 ByteMD 編輯器中使用自定義插件

bytemd-plugin-custom.ts 導入到你的 ByteMarkdownEditor.tsx 中,并將其添加到 plugins 數組。

// components/Editor/ByteMarkdownEditor.tsx
'use client';import React, { useState } from 'react';
import { Editor } from '@bytemd/react';
import gfm from '@bytemd/plugin-gfm';
import highlight from '@bytemd/plugin-highlight';
import math from '@bytemd/plugin-math';
import gemoji from '@bytemd/plugin-gemoji';
import frontmatter from '@bytemd/plugin-frontmatter';// 導入你的自定義插件
import bytemdPluginCustom from '../../plugins/bytemd-plugin-custom';// Import Bytemd styles
import 'bytemd/dist/index.css';
import 'highlight.js/styles/github.css'; // 代碼高亮主題
import 'katex/dist/katex.css'; // 數學公式樣式// 定義插件數組
const plugins = [gfm(), // 提供 ==highlight== 語法的支持highlight(),math(),gemoji(),frontmatter(),// 添加你的自定義插件bytemdPluginCustom({ highlightKeywords: ['重要', '注意', '提示'] }),
];interface ByteMarkdownEditorProps {initialValue?: string;onChange?: (value: string) => void;
}const ByteMarkdownEditor: React.FC<ByteMarkdownEditorProps> = ({ initialValue = '', onChange }) => {const [value, setValue] = useState(initialValue);const handleChange = (newValue: string) => {setValue(newValue);if (onChange) {onChange(newValue);}};return (<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}><Editorvalue={value}plugins={plugins}onChange={handleChange}/></div>);
};export default ByteMarkdownEditor;

運行效果:

  • 你的 ByteMD 編輯器工具欄會多出一個日期時間圖標的按鈕。點擊它,會在編輯器光標處插入當前的日期時間。
  • 在編輯器中輸入 “這是一段重要內容” 或 “請注意以下幾點”,在預覽模式下,“重要”和“注意”字樣將以高亮(通常是黃色背景)顯示,因為 plugin-gfm==...== 轉換為 <mark> 標簽。

總結向面試官介紹自定義插件


面試官您好,我來詳細介紹一下 ByteMD 的插件系統,并結合自定義插件的實現。

ByteMD 的插件系統是其高度可擴展性的核心。它允許我們在不修改核心庫代碼的前提下,輕松地添加、修改或擴展編輯器的行為和功能。

其設計精妙之處在于:

  1. 分階段的鉤子機制: 插件通過實現不同的鉤子函數,在 ByteMD 內部的 Markdown 處理流程中精確介入。

    • remark 鉤子: 負責在 Markdown 解析成 MDAST (Markdown Abstract Syntax Tree) 后,對 AST 進行操作。例如,我可以定義一個 remark 插件來識別自定義的 Markdown 語法,或者對內容進行前置處理(如我自定義插件中的高亮關鍵詞處理,將普通文本轉換為 ==關鍵詞== 形式)。
    • rehype 鉤子: 負責在 MDAST 轉換為 HAST (Hypertext Abstract Syntax Tree) 后,對 HTML 的 AST 進行操作。這允許我對最終生成的 HTML 結構進行修改,例如為圖片添加 lazy-load 屬性,或者將特定 AST 節點渲染為復雜的自定義 HTML 結構。
    • editorEffect 鉤子: 允許我直接與底層的編輯器實例(如 CodeMirror)進行交互。這對于實現圖片拖拽上傳、自定義快捷鍵、或者監聽編輯器狀態變化等功能至關重要。
    • viewerEffect 鉤子: 允許我在預覽區域的 HTML 渲染完成后,對其 DOM 進行操作。這適合于初始化第三方渲染庫(如 Mermaid、ECharts),或者對預覽內容進行后期處理。
    • actions 鉤子: 最直觀的擴展方式,允許我在工具欄添加自定義按鈕,實現特定的交互功能,例如我自定義插件中的“插入日期時間”按鈕。
  2. 擁抱 unified 生態: ByteMD 沒有“重新發明輪子”,而是巧妙地利用了 unified 這一成熟且強大的內容處理框架。這使得插件的開發能夠復用 remarkrehype 社區大量的現有插件和工具,極大地加速了開發。

以我剛剛實現的自定義插件為例,它實現了兩個功能:

  1. “插入日期時間”按鈕:

    • 我通過 actions 鉤子在 ByteMD 的工具欄添加了一個自定義按鈕。
    • 在按鈕的 handler 中,我利用 editorEffect 鉤子提供給我的 editor 實例(即 CodeMirror 實例),調用其 replaceSelection() 方法,實現了在光標處插入當前日期時間字符串的功能。這體現了 actionseditorEffect 在 UI 交互和編輯器控制上的協同作用。
  2. 高亮特定關鍵詞:

    • 我利用 remark 鉤子,注冊了一個自定義的 remark 插件 (remarkCustomHighlight)。
    • 這個插件會遍歷 Markdown 的 AST,查找預定義的關鍵詞(如“重要”、“注意”)。
    • 一旦找到,它會修改 AST 中的文本節點,將關鍵詞用 ==...== 包裹起來。由于 ByteMD 的 plugin-gfm 已經內置了對 ==text== 渲染為 <mark> 標簽的支持,我得以復用其渲染能力,實現了在預覽時自動高亮關鍵詞的效果,而無需編寫復雜的 rehype 邏輯。這展示了如何通過利用現有插件的能力來簡化自定義。

總之,ByteMD 的插件系統是一個設計精良、高度開放的架構。它通過分層的鉤子和對 unified 生態的集成,使得開發者可以靈活地在不同階段對 Markdown 內容進行處理和定制編輯器行為,從而構建出滿足各種復雜需求的強大內容創作工具。


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

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

相關文章

每日一練之 Lua 表

Lua 的 table 是什么數據結構&#xff1f;如何創建和訪問&#xff1f; 數據結構:Lua的table是一種哈希表&#xff0c;使用鍵值對存儲數據&#xff0c;支持動態擴容 創建方式: local t1 {} local t2 {10,20,30} local t3 {name"Alice",age25}訪問方式&#xff1a…

實現自動胡批量抓取唯品會商品詳情數據的途徑分享(官方API、網頁爬蟲)

在電商領域&#xff0c;數據就是企業的核心資產。無論是市場分析、競品研究&#xff0c;還是精準營銷&#xff0c;都離不開對大量商品詳情數據的深入挖掘。唯品會作為知名的電商平臺&#xff0c;其豐富的商品信息對于眾多從業者而言極具價值。本文將詳細探討實現自動批量抓取唯…

Zephyr 高階實踐:徹底講透 west 構建系統、模塊管理與跨平臺 CI/CD 配置

本文是 Zephyr 項目管理體系的高階解構與實戰指南&#xff0c;全面覆蓋 west 構建系統原理、模塊解耦與 west.yml 多模塊維護機制&#xff0c;結合企業級多平臺 CI/CD 落地流程&#xff0c;深入講解如何構建可靠、可維護、跨芯片架構的一體化 Zephyr 工程。 一、為什么 Zephyr …

我開源了一套springboot3快速開發模板

我開源了一套springboot3快速開發模板 開箱即用、按需組合、可快速二次開發的后端通用模板。 ? 主要特性 Spring Boot 3.x Java 17&#xff1a;跟隨 Spring 最新生態&#xff0c;利用現代語法特性。多模塊分層&#xff1a;common 抽象通用能力、starter 負責啟動、modules…

OpenCV CUDA模塊設備層-----在GPU上計算兩個uchar1類型像素值的反正切(arctangent)比值函數atan2()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 對輸入的兩個 uchar1 像素值 a 和 b&#xff0c;先分別歸一化到 [0.0, 1.0] 浮點區間&#xff0c;然后計算它們的 四象限反正切函數。 函數原型…

從C++編程入手設計模式——觀察者模式

從C編程入手設計模式——觀察者模式 ? 觀察者模式簡直就是字如其名&#xff0c;觀察觀察&#xff0c;觀察到了告訴別人。觀察手的作用如此&#xff0c;觀察者模式的工作機制也是如此。這個模式的核心思路是&#xff1a;一個對象的狀態發生變化時&#xff0c;自動通知依賴它的…

MITM 中間人攻擊

?據Akamai 2023網絡安全報告顯示&#xff0c;MITM攻擊在數據泄露事件中占比達32.7%&#xff0c;平均每次事件造成企業損失$380,000? ?NIST研究指出&#xff1a;2022-2023年高級MITM攻擊增長41%&#xff0c;近70%針對金融和醫療行業? 一、MITM攻擊核心原理與技術演進 1. 中…

llama_index chromadb實現RAG的簡單應用

此demo是自己提的一個需求&#xff1a;用modelscope下載的本地大模型實現RAG應用。畢竟大模型本地化有利于微調&#xff0c;RAG使內容更有依據。 為什么要用RAG&#xff1f; 由于大模型存在一定的局限性&#xff1a;知識時效性不足、專業領域覆蓋有限以及生成結果易出現“幻覺…

TDMQ CKafka 版事務:分布式環境下的消息一致性保障

解鎖 CKafka 事務能力的神秘面紗 在當今數字化浪潮下&#xff0c;分布式系統已成為支撐海量數據處理和高并發業務的中流砥柱。但在這看似堅不可摧的架構背后&#xff0c;數據一致性問題卻如影隨形&#xff0c;時刻考驗著系統的穩定性與可靠性。 CKafka 作為分布式流處理平臺的…

常見的負載均衡算法

常見的負載均衡算法 在實現水平擴展過程中&#xff0c;負載均衡算法是決定請求如何在多個服務實例間分配的核心邏輯。一個合理的負載均衡策略能夠有效分散系統壓力&#xff0c;提升系統吞吐能力與穩定性。 負載均衡算法可部署在多種層級中&#xff0c;如七層HTTP反向代理&…

數據結構轉換與離散點生成

在 C 開發中&#xff0c;我們常常需要在不同的數據結構之間進行轉換&#xff0c;以滿足特定庫或框架的要求。本文將探討如何將 std::vector<gp_Pnt> 轉換為 QVector<QPointF>&#xff0c;并生成特定范圍內的二維離散點。 生成二維離散點 我們首先需要生成一系列…

零基礎學習Redis(12) -- Java連接redis服務器

在我們之前的內容中&#xff0c;我們會發現通過命令行操作redis是十分不科學的&#xff0c;所以redis官方提供了redis的應用層協議RESP&#xff0c;更具這個協議可以實現一個和redis服務器通信的客戶端程序&#xff0c;來簡化和完善redis的使用。現階段有很多封裝了RESP協議的庫…

clangd LSP 不能找到項目中的文件

clangd LSP 不能找到項目中的文件 clangd LSP 不能找到項目中的文件 clangd LSP 不能找到項目中的文件 Normally you need to create compile_commands.json。 如果你使用 cmake 作為構建工具&#xff0c;請執行下面的命令&#xff1a; cmake -DCMAKE_EXPORT_COMPILE_COMMAN…

【內存】Linux 內核優化實戰 - vm.overcommit_memory

目錄 vm.overcommit_memory 解釋一、概念與作用二、參數取值與含義三、相關參數與配置方式四、實際應用場景建議五、注意事項 vm.overcommit_memory 解釋 一、概念與作用 vm.overcommit_memory 是 Linux 內核中的一個參數&#xff0c;用于控制內存分配的“過度承諾”&#xf…

Python:.py文件轉換為雙擊可執行的Windows程序(版本2)

流程步驟&#xff1a; 這個流程圖展示了將 Python .py 文件轉換為 Windows 可執行程序的完整過程&#xff0c;主要包括以下步驟&#xff1a; 1、準備 Python文件&#xff0c;確保代碼可獨立運行 2、安裝打包工具&#xff08;如 PyInstaller&#xff09; 3、打開命令提示符并定位…

【請關注】mysql一些經常用到的高級SQL

經常去重復數據&#xff0c;數據需要轉等操作&#xff0c;匯總高級SQL MySQL操作 一、數據去重&#xff08;Data Deduplication&#xff09; 去重常用于清除重復記錄&#xff0c;保留唯一數據。 1. 使用DISTINCT關鍵字去重單列 -- 從用戶表中獲取唯一的郵箱地址 SELECT DISTIN…

RA4M2開發涂鴉模塊CBU(2)----配置按鍵開啟LED

RA4M2開發涂鴉模塊CBU.2--配置按鍵開啟LED 概述視頻教學樣品申請硬件準備參考程序按鍵口配置中斷回調函數主程序 概述 本實驗演示如何在 Renesas RA4M2 單片機上使用 GPIO 輸入&#xff08;按鍵&#xff09; 觸發 GPIO 輸出&#xff08;LED&#xff09;&#xff0c;并使用e2st…

Linux——Json

一 概念 json是一種輕量級&#xff0c;基于文本的&#xff0c;可讀的數據交換格式&#xff0c;能夠讓數據在不同系統&#xff08;比如前端—后端&#xff0c;服務器—客戶端&#xff09;間方便傳遞/存儲。在編程語言中都內置了處理json數據的方法 二 語法規則 1. 數據格式&a…

大模型之微調篇——指令微調數據集準備

寫在前面 高質量數據的準備是微調大模型的重中之重&#xff0c;一些高質量的數據集可能遠比模型性能更佳重要。 我是根據自己的數據照著B站up code花園LLaMA Factory 微調教程&#xff1a;如何構建高質量數據集&#xff1f;_嗶哩嗶哩_bilibili做的。 數據集格式 在LLaMA Fa…

LVS—DR模式

LVS—DR模式 LVS DR 模式詳細簡介 一、模式定義與核心原理 LVS DR&#xff08;Direct Routing&#xff09;模式&#xff0c;即直接路由模式&#xff0c;是 Linux Virtual Server&#xff08;LVS&#xff09;實現負載均衡的經典模式之一&#xff0c;工作于網絡四層&#xff0…