有道云docx转换markdown,导入hugo发布到github page,多平台发布适配

news2024/11/10 14:07:20

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

有道云导出docx

有道云笔记右上角更多按钮选择【导出为Word】,可以导出docx文档
image.png

docx转换markdown

尝试了几个docx转markdown的python库后,最终选择了python-mammoth,轻量,效率高,可自定义转换满足特定需求。

python-mammoth

python-mammoth 是一个用于将 Microsoft Word (DOCX) 文档转换为 HTML 或 Markdown 的 Python 库。

github地址:https://github.com/mwilliamson/python-mammoth

安装 python-mammoth

pip install mammoth

自定义代码块样式

通过自定义 transform 来实现自定义的代码块样式来支持有道云docx的代码块

def ynote_docx_markdown_transform(document):
    ...
    pass

result = convert_to_markdown(docx_file, transform_document=ynote_docx_markdown_transform)

通过在自定义 transform 断点调试可以看到 document 都是由一个一个 Paragraph 组成的,代码块的 Bookmark 的 name 都是相同的,由此代码块其中一个特征就是相同且相邻的 Bookmark name。
image.png

但是有的代码块只是单独的一段
image.png
这时可以通过自定义 代码/bash 特征判断该 Paragraph 中的 Text 是不是一段 代码/bash。

def is_possible_code_or_bash(text):
    # 常见的代码关键字
    code_keywords = [
        r'\bif\b', r'\bfor\b', r'\bwhile\b', r'\bdef\b', r'\bclass\b', r'\breturn\b', r'\bimport\b',
        r'\bint\b', r'\bfloat\b', r'\bmain\b', r'\binclude\b', r'#include', r'\becho\b', r'\bcd\b',
        r'\bgrep\b', r'\bexit\b', r'\belse\b', r'\belif\b', r'#!/bin/bash', r'&&', r'\|\|', r'\$', r'\>',
        r'\<'
    ]

    # 常见的 Bash 命令
    bash_keywords = [r'::', r'Get-Item ']

    # 以这些符号开头的都当 bash 处理
    start_keywords = [r'# ', r'git ', r'choco ', r'hugo', r'cd ', r'pip ', r'pip3 ', r'conda ', r'sudo ']

    # 检查是否包含代码关键字
    for keyword in code_keywords:
        if re.search(keyword, text):
            return keyword

    # 检查是否包含 Bash 命令
    for keyword in bash_keywords:
        if re.search(keyword, text):
            return keyword

    # 检查是否包含代码符号
    for keyword in start_keywords:
        if text.startswith(keyword):
            return keyword

    return None

实现步骤:

  1. bookmark_name相同且相邻的判定为代码块
  2. 其它不相邻的数据通过特征值判断是否可能是代码
  3. 在代码块前后加上代码块符号
def ynote_docx_markdown_transform(document):
    """
    有道云 docx 文件转换 markdown 文件的 transform
    :param document: 文档对象
    :return: 转换后的文档对象
    """

    # bookmark_name相同且相邻的判定为代码块
    bookmark_name_list = []
    for index, element in enumerate(document.children):
        if isinstance(element, Paragraph) and element.children:
            bookmark = element.children[0]
            if isinstance(element.children[0], Bookmark):
                bookmark_name_list.append(bookmark.name)
    indices = find_adjacent_duplicates_indices(bookmark_name_list)

    # 过滤出非相邻的数据
    filtered_indices = filter_out_indices(document.children, indices)
    # 其它不相邻的数据通过特征值判断是否可能是代码
    for index in filtered_indices:
        element = document.children[index]
        if len(element.children) >= 2:
            run = element.children[1]
            if isinstance(run, Run):
                text = run.children[0]
                if isinstance(text, Text):
                    feature = is_possible_code_or_bash(text.value)
                    if feature:
                        print('=====================================找到代码块==================================================================')
                        print(run.children[0].value)
                        print(f'特征:{feature}')
                        print('===============================================================================================================')
                        indices.append((index, index))

    # 根据开始索引重新排序
    indices.sort(key=lambda x: x[0])

    # 在代码块前后加上代码块符号
    offset = 0
    for item in indices:
        value_before = Paragraph(
            children=[Text('```')],
            style_id='code',
            style_name='Code',
            numbering=None,
            alignment=None,
            indent=None
        )
        value_after = Paragraph(
            children=[Text('```')],
            style_id='code',
            style_name='Code',
            numbering=None,
            alignment=None,
            indent=None
        )
        insert_before_and_after(document.children, item[0] + offset, item[1] + offset, value_before, value_after)
        offset += 2

    return document

自定义MarkdownWriter

创建一个 CustomMarkdownWriter 继承 MarkdownWriter 并重写对应的方法,实现如下需求:

  1. 去掉锚点标签(默认会生成锚点标签 ,通常用于生成跳转链接的目标位置)
  2. 去掉转义处理(默认会对特殊字符进行转义处理,这里为了保持与文档一致,不需要转义)
  3. 修改 Paragraph 输出时结尾默认两个换行改为一个换行(默认两个换行让文档看起来很松散)
class CustomMarkdownWriter(MarkdownWriter):
    """
    自定义的 MarkdownWriter
    """

    def __init__(self):
        super().__init__()
        self.custom_markdown_writers()

    @staticmethod
    def custom_markdown_writers():
        """
        修改 Paragraph 输出时结尾默认两个换行改为一个换行
        """
        from mammoth.writers.markdown import _writers, _Wrapped
        _writers['p'] = _Wrapped("", "\n")

    @staticmethod
    def register_writer():
        """
        注册自定义的 CustomMarkdownWriter
        """
        from mammoth.writers import _writers
        _writers['markdown'] = CustomMarkdownWriter

    def text(self, text):
        """
        去掉转义处理
        """
        self._fragments.append(text)

    def _write_anchor(self, attributes):
        """
        去掉描点
        """
        pass

完整代码

# 将有道云导出的 docx 转换为 markdown
from mammoth import convert_to_markdown
from mammoth.documents import Paragraph, Text, Bookmark, Run
import re
from mammoth.writers.markdown import MarkdownWriter


def find_adjacent_duplicates_indices(string_list):
    """
    查找字符串列表中值相同且相邻的部分
    :param string_list: 字符串列表
    :return: 目标的开始索引和结束索引列表
    """
    if not string_list:
        return []

    result = []
    start = 0

    for i in range(1, len(string_list)):
        if string_list[i] != string_list[start]:
            if i - 1 > start:
                result.append((start, i - 1))
            start = i

    # 处理列表的最后一组相同相邻项
    if len(string_list) - 1 > start:
        result.append((start, len(string_list) - 1))

    return result


def insert_before_and_after(lst, start_index, end_index, value_before, value_after):
    """
    在列表中指定开始和结束位置前后插入值
    :param lst: 列表
    :param start_index: 开始索引
    :param end_index: 结束索引
    :param value_before: 前插值
    :param value_after: 后插值
    """
    # 在指定索引前插入值
    lst.insert(start_index, value_before)

    # 因为插入了一个元素,索引位置向后移动1位,而且插入在end_index后面,所以在 index + 2 处插入值
    if end_index + 2 < len(lst):
        lst.insert(end_index + 2, value_after)
    else:
        lst.append(value_after)


def filter_out_indices(data_list, index_ranges):
    """
    过滤掉在指定索引范围内的索引
    :param data_list: 数据列表
    :param index_ranges: 执行的索引范围列表
    :return: 返回过滤后的索引列表
    """
    result = []
    for i in range(len(data_list)):
        # 检查当前索引是否在任何一个给定的范围内
        in_range = any(start <= i <= end for start, end in index_ranges)
        if not in_range:
            result.append(i)
    return result


def is_possible_code_or_bash(text):
    # 常见的代码关键字
    code_keywords = [
        r'\bif\b', r'\bfor\b', r'\bwhile\b', r'\bdef\b', r'\bclass\b', r'\breturn\b', r'\bimport\b',
        r'\bint\b', r'\bfloat\b', r'\bmain\b', r'\binclude\b', r'#include', r'\becho\b', r'\bcd\b',
        r'\bgrep\b', r'\bexit\b', r'\belse\b', r'\belif\b', r'#!/bin/bash', r'&&', r'\|\|', r'\$', r'\>',
        r'\<'
    ]

    # 常见的 Bash 命令
    bash_keywords = [r'::', r'Get-Item ']

    # 以这些符号开头的都当 bash 处理
    start_keywords = [r'# ', r'git ', r'choco ', r'hugo', r'cd ', r'pip ', r'pip3 ', r'conda ', r'sudo ']

    # 检查是否包含代码关键字
    for keyword in code_keywords:
        if re.search(keyword, text):
            return keyword

    # 检查是否包含 Bash 命令
    for keyword in bash_keywords:
        if re.search(keyword, text):
            return keyword

    # 检查是否包含代码符号
    for keyword in start_keywords:
        if text.startswith(keyword):
            return keyword

    return None


def ynote_docx_markdown_transform(document):
    """
    有道云 docx 文件转换 markdown 文件的 transform
    :param document: 文档对象
    :return: 转换后的文档对象
    """

    # bookmark_name相同且相邻的判定为代码块
    bookmark_name_list = []
    for index, element in enumerate(document.children):
        if isinstance(element, Paragraph) and element.children:
            bookmark = element.children[0]
            if isinstance(element.children[0], Bookmark):
                bookmark_name_list.append(bookmark.name)
    indices = find_adjacent_duplicates_indices(bookmark_name_list)

    # 过滤出非相邻的数据
    filtered_indices = filter_out_indices(document.children, indices)
    # 其它不相邻的数据通过特征值判断是否可能是代码
    for index in filtered_indices:
        element = document.children[index]
        if len(element.children) >= 2:
            run = element.children[1]
            if isinstance(run, Run):
                text = run.children[0]
                if isinstance(text, Text):
                    feature = is_possible_code_or_bash(text.value)
                    if feature:
                        print('=====================================找到代码块==================================================================')
                        print(run.children[0].value)
                        print(f'特征:{feature}')
                        print('===============================================================================================================')
                        indices.append((index, index))

    # 根据开始索引重新排序
    indices.sort(key=lambda x: x[0])

    # 在代码块前后加上代码块符号
    offset = 0
    for item in indices:
        value_before = Paragraph(
            children=[Text('```')],
            style_id='code',
            style_name='Code',
            numbering=None,
            alignment=None,
            indent=None
        )
        value_after = Paragraph(
            children=[Text('```')],
            style_id='code',
            style_name='Code',
            numbering=None,
            alignment=None,
            indent=None
        )
        insert_before_and_after(document.children, item[0] + offset, item[1] + offset, value_before, value_after)
        offset += 2

    return document


class CustomMarkdownWriter(MarkdownWriter):
    """
    自定义的 MarkdownWriter
    """

    def __init__(self):
        super().__init__()
        self.custom_markdown_writers()

    @staticmethod
    def custom_markdown_writers():
        """
        修改 Paragraph 输出时结尾默认两个换行改为一个换行
        """
        from mammoth.writers.markdown import _writers, _Wrapped
        _writers['p'] = _Wrapped("", "\n")

    @staticmethod
    def register_writer():
        """
        注册自定义的 CustomMarkdownWriter
        """
        from mammoth.writers import _writers
        _writers['markdown'] = CustomMarkdownWriter

    def text(self, text):
        """
        去掉转义处理
        """
        self._fragments.append(text)

    def _write_anchor(self, attributes):
        """
        去掉描点
        """
        pass


def convert_docx_to_markdown(docx_path, output_path):
    with open(docx_path, "rb") as docx_file:
        # 使用自定义的 MarkdownWriter 进行转换
        CustomMarkdownWriter.register_writer()

        result = convert_to_markdown(docx_file, transform_document=ynote_docx_markdown_transform)

        markdown = result.value

        with open(output_path, "w", encoding="utf-8") as md_file:
            md_file.write(markdown)


# 路径设置
docx_path = r"D:\hugo\0成本通过Hugo和GitHub Pages搭建博客.docx"
output_path = "output.md"

# 转换 DOCX 为 Markdown
convert_docx_to_markdown(docx_path, output_path)

查看效果

在线markdown编辑器:https://pandao.github.io/editor.md/

image.png

导入hugo发布到github page

把转换后的 markdown 添加到 hugo 并部署到 github page

添加 hugo header

在转换后的 markdown 头部添加一下 hugo header 信息,并把 markdown 输出到 hugo 的 content/posts 目录下

from datetime import datetime, timezone, timedelta


def add_hugo_header(markdown, title):
    date = datetime.now(timezone(timedelta(hours=8))).isoformat()
    return f"+++\ntitle = '{title}'\ndate = {date}\ndraft = false\n+++\n{markdown}"


def convert_docx_to_markdown(docx_path, output_dir):
    with open(docx_path, "rb") as docx_file:
        title = os.path.basename(docx_path).split('.')[0]

        output_path = os.path.join(output_dir, f'{title}.md')

        # 使用自定义的 MarkdownWriter 进行转换
        CustomMarkdownWriter.register_writer()

        result = convert_to_markdown(docx_file, transform_document=ynote_docx_markdown_transform)

        markdown = result.value

        # 添加 hugo header
        markdown = add_hugo_header(markdown, title)

        with open(output_path, "w", encoding="utf-8") as md_file:
            md_file.write(markdown)


# 路径设置
docx_path = r"D:\hugo\0成本通过Hugo和GitHub Pages搭建博客.docx"
output_dir = r"D:\hugo\cyrus\content\posts"

# 转换 DOCX 为 Markdown
convert_docx_to_markdown(docx_path, output_dir)

发布到github page

# 重新生成页面
hugo

# 提交代码到github
git add .
git commit -m "0成本通过Hugo和GitHub Pages搭建博客"
git push

最终效果:
image.png

实现markdown多平台发布

由于图片是内嵌的base64格式的,不是所有平台的markdown编辑器都支持。
简书、稀土掘金、知乎都不支持。CSDN需要做如下修改才能正常显示图片:

1. 需要将图片从
2. ![image.png](data:image/png;base64,...)

转换为:

![image][tmp]

[tmp]:data:image/png;base64,...

在csdn编辑器上才能正常显示

所以,为了能兼容各平台的 markdown 编辑器,解决方案如下:

  1. 在 gitee 创建一个仓库作为图库
  2. 解析 markdown 中的所有图片,并以图片 base64 数据的 md5 命名保存到本地
  3. 把本地图片都上传到 gitee 图库
  4. 修改 markdown 中所有 base64 图片为 gitee 图库中图片的链接

创建gitee图库

image.png
把仓库 clone 到本地。

保存base64图片到图库

通过正则去匹配 markdown 中所有 base64 图片,并把图片数据都保存到本地 gitee 图库,文件以 base64 图片数据的 md5 命名

import re
import os
import hashlib
import base64


def save_base64_images(markdown_content, output_dir):
    # 创建输出目录(如果不存在)
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 正则表达式匹配 base64 图片数据
    base64_pattern = re.compile(r'data:image/(png|jpeg|jpg|gif);base64,([A-Za-z0-9+/=]+)')

    # 查找所有匹配的 base64 图片数据
    matches = base64_pattern.findall(markdown_content)

    for match in matches:
        image_type = match[0]
        base64_data = match[1]

        # 计算 base64 数据的 MD5 哈希值
        md5_hash = hashlib.md5(base64_data.encode('utf-8')).hexdigest()

        # 解码 base64 数据
        image_data = base64.b64decode(base64_data)

        # 生成文件路径
        image_filename = f"{md5_hash}.{image_type}"
        image_path = os.path.join(output_dir, image_filename)

        # 保存图片到指定目录
        with open(image_path, "wb") as image_file:
            image_file.write(image_data)

        print(f"Saved image: {image_path}")


def save_base64_images_from_file(markdown_file_path, output_dir):
    # 读取本地 Markdown 文件内容
    with open(markdown_file_path, "r", encoding="utf-8") as file:
        markdown_content = file.read()
        save_base64_images(markdown_content, output_dir)


# markdown 文件路径
markdown_file_path = r"D:\hugo\cyrus\content\posts\0成本通过Hugo和GitHub Pages搭建博客.md"
# 指定保存图片的目录
images_dir = r"D:\hugo\images"

# 保存图片
save_base64_images_from_file(markdown_file_path, images_dir)

图片都保存到本地图库后,通过 git 把图片都 push 到 gitee 仓库。

生成多平台发布版本的 markdown

图片上传完成后,点击图片,点击【原始数据】就可以看到图片的链接了

image.png

图片的链接格式如下:
https://gitee.com/cyrus-studio/images/raw/master/0432ae07a167ea4c79f3cda193d0d1bc.png

每个图片的链接前面部分都一样,只是文件名的md5不一样,接下来需要把 markdown 中的 base64 图片都换成 gitee 图库中图片的链接,并生成新的 markdown 即可。

实现步骤:

  1. 读取 markdown,并移除 hugo header
  2. 正则表达式匹配 base64 图片数据,计算md5,替换为 gitee 图库链接
  3. 将结果写入新的 Markdown 文件
import os
import re
import hashlib


def remove_hugo_header(markdown_content):
    # 正则匹配 Hugo front matter(通常在文件的开头用三条+包裹)
    front_matter_pattern = re.compile(r'^\+\+\+\s*\n.*?\n\+\+\+\s*\n', re.DOTALL)
    # 使用正则表达式去除 front matter
    return re.sub(front_matter_pattern, '', markdown_content)


def replace_base64_images_with_links(markdown_file_path, output_dir, base_url):
    # 读取本地 Markdown 文件内容
    with open(markdown_file_path, "r", encoding="utf-8") as file:
        markdown_content = file.read()

    # 去除 Hugo header(front matter)
    markdown_content = remove_hugo_header(markdown_content)

    # 获取原文件名并构建新的文件路径
    original_filename = os.path.basename(markdown_file_path)
    output_file_path = os.path.join(output_dir, original_filename)

    # 创建输出目录(如果不存在)
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 正则表达式匹配 base64 图片数据
    base64_pattern = re.compile(r'(data:image/(png|jpeg|jpg|gif);base64,([A-Za-z0-9+/=]+))')

    def replace_with_link(match):
        base64_data = match.group(3)

        # 计算 base64 数据的 MD5 哈希值
        md5_hash = hashlib.md5(base64_data.encode('utf-8')).hexdigest()

        # 构建新的图片链接
        image_url = f"{base_url}/{md5_hash}.png"

        return image_url

    # 替换所有 base64 图片为链接
    new_markdown_content = re.sub(base64_pattern, replace_with_link, markdown_content)

    # 将结果写入新的 Markdown 文件
    with open(output_file_path, "w", encoding="utf-8") as output_file:
        output_file.write(new_markdown_content)

    print(f"Replaced base64 images with links and removed Hugo header in {output_file_path}")


# markdown 文件路径
markdown_file_path = r"D:\hugo\cyrus\content\posts\0成本通过Hugo和GitHub Pages搭建博客.md"
# 多平台发布版本的 markdown 保存目录
markdown_dir = r"D:\hugo\markdown"
# 图片的基础 URL
images_base_url = "https://gitee.com/cyrus-studio/images/raw/master"

replace_base64_images_with_links(markdown_file_path, markdown_dir, images_base_url)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2041481.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.2 数据库管理系统的基本原理

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; 工&#x1f497;重&#x1f497;hao&#x1f497;&#xff1a;野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题.…

子网掩码是什么?

子网掩码&#xff08;Subnet Mask&#xff09;是用于划分网络的一个32位的二进制数&#xff0c;用于指示IP地址中哪些位用于网络标识&#xff0c;哪些位用于主机标识。 在IPv4网络中&#xff0c;IP地址由32位二进制数组成&#xff0c;通常表示为四个十进制数&#xff0c;每个数…

Leetcode—1006. 笨阶乘【中等】

2024每日刷题&#xff08;156&#xff09; Leetcode—1006. 笨阶乘 实现代码 class Solution { public:int clumsy(int n) {stack<int> st;st.push(n);n--;int idx 0;while(n ! 0) {if(idx % 4 0) {int num st.top() * n;st.pop();st.push(num);} else if(idx % 4 …

plsql如何连接sql server?plsql连接oracle数据库如何配置

在当今企业数据管理和应用开发中&#xff0c;数据库的互联互通已成为常态。特别是在多数据库环境下&#xff0c;如Oracle和SQL Server的结合使用&#xff0c;为企业提供了更广阔的数据处理能力。PL/SQL作为Oracle数据库的过程化扩展语言&#xff0c;能够高效地管理Oracle数据库…

应急响应:病毒处理的方法---实战案例.(手动版)

什么是应急响应. 一个组织为了 应对 各种网络安全 意外事件 的发生 所做的准备 以及在 事件发生后 所采取的措施 。说白了就是别人攻击你了&#xff0c;你怎么把这个攻击还原&#xff0c;看看别人是怎么攻击的&#xff0c;然后你如何去处理&#xff0c;这就是应急响应。 目录&…

带你速通C语言——位运算符、结构运算符与指针运算符(5)

位运算符、结构运算符与指针运算符 C语言的位运算符、结构运算符和指针运算符是对数据的更底层操作&#xff0c;使得C语言尤其适合进行系统编程和处理复杂的内存管理任务。下面详细介绍这些运算符。 1.位运算符 位运算符作用于整数类型的操作数的二进制位。以下是C语言中可用的…

报SBAT self-check failed: Security Policy Violation突然开不了机

台式机一直用的好好的没什么问题&#xff0c;早晨突然开机就关机提示&#xff1a; 查了一下网上资料&#xff0c;在BIOS里面搜“安全启动”改为禁用就行&#xff0c;该电脑微星主板直接由开启改为禁用&#xff0c;重启进入系统。很奇怪&#xff0c;一直用的没啥&#xff0c;突然…

Spring AOP应用指南:概念、通知与表达式分析

目录 一.AOP的基础概念 二.Spring AOP的应用场景 三.Spring AOP的核心概念 ▐ 切点(Pointcut) ▐ 连接点(Join Point) ▐ 通知(Advice) ▐ 切面(Aspect) 通知类型 四.PointCut与Order 切面优先级 五.切点表达式 execution(...)表达式 annotation表达式 一.AOP的基…

Java spring SSM框架--mybatis

一、介绍 Spring 框架是一个资源整合的框架&#xff0c;可以整合一切可以整合的资源&#xff08;Spring 自身和第三方&#xff09;&#xff0c;是一个庞大的生态&#xff0c;包含很多子框架&#xff1a;Spring Framework、Spring Boot、Spring Data、Spring Cloud…… 其中Spr…

NLP实战二:Pytorch实现TextRNN文本分类

中文数据集 我从THUCNews中抽取了20万条新闻标题&#xff0c;已上传至github&#xff0c;文本长度在20到30之间。一共10个类别&#xff0c;每类2万条。 类别&#xff1a;财经、房产、股票、教育、科技、社会、时政、体育、游戏、娱乐。 数据集划分&#xff1a; 数据集数据量…

Python 接口自动化测试中的深拷贝与浅拷贝~

前言 在编写接口自动化测试脚本时&#xff0c;我们经常需要复制数据结构来模拟不同的测试场景。Python 提供了两种拷贝机制&#xff1a;浅拷贝和深拷贝。理解这两种拷贝的区别对保证测试数据的一致性和准确性至关重要。 浅拷贝 vs 深拷贝 浅拷贝&#xff1a;只复制引用&#…

软件架构:依赖倒置原则的魅力

依赖倒置原则&#xff08;Dependency Inversion Principle, DIP&#xff09;是面向对象设计的基本原则之一&#xff0c;由罗伯特C马丁&#xff08;Robert C. Martin&#xff09;提出。这一原则旨在降低系统中各个组件之间的耦合度&#xff0c;提高系统的可维护性和可扩展性。 …

四川正信法律:借钱不还报警有没有用

在日常生活中&#xff0c;金钱往来是人际交往中不可或缺的一部分。然而&#xff0c;当借钱不还成为一种普遍现象时&#xff0c;人们往往会感到困惑和无奈。那么&#xff0c;面对借钱不还的情况&#xff0c;报警是否有用呢? 我们要明确一点&#xff0c;借钱不还属于民事纠纷&am…

注意力机制 — 它是什么以及它是如何工作的

一、说明 注意力机制是深度学习领域的一个突破。它们帮助模型专注于数据的重要部分&#xff0c;并提高语言处理和计算机视觉等任务的理解和性能。这篇文章将深入探讨深度学习中注意力的基础知识&#xff0c;并展示其背后的主要思想。 二、注意力机制回顾 在我们谈论注意力之前&…

TcpSocket在切后台后如何保活

1&#xff09;TcpSocket在切后台后如何保活 2&#xff09;Magica Clothes 2插件与Burst编译问题 3&#xff09;粒子拖尾合批失败怎么办 4&#xff09;如何让射线追踪跟随我FPS游戏的十字准星进行移动 这是第398篇UWA技术知识分享的推送&#xff0c;精选了UWA社区的热门话题&…

适合学生党的运动耳机都有哪些?五大适合学生党的运动耳机推荐

2024年春季&#xff0c;开放式蓝牙耳机就凭借“佩戴舒适、开放安全”等优势火热出圈&#xff0c;这让各大音频厂商更新迭代速度不断加快&#xff0c;新品层出不穷。而用户面对市场上琳琅满目的开放式蓝牙耳机&#xff0c;一时间也不知道如何选择。那么对于学生党来说&#xff0…

linux 基本指令讲解 下

基本指令 date 显示 date 指定格式显示时间:date%Y:%m:%d(冒号可以随便改) 在显示方面 %H : 小时(00..23) %M : 分钟(00..59) %S : 秒(00..61) %X : 相当于 %H:%M:%S %d : 日 (01..31) %m : 月份 (01..12) %Y : 完整年份 (0000..9999) %F : 相当于 %Y-%m-%d在时间设置方面 date…

依赖注入+中央事件总线:Vue 3组件通信新玩法

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue篇专栏内容:Vue-依赖注入-中央事件总线 大家好&#xff0c;依旧青山&#xff0c; 最近呢也随着需求的变更调优…

Prometheus部署和基本操作

1 项目目标 &#xff08;1&#xff09;对Prometheus有基本的了解 &#xff08;2&#xff09;能够部署出一套Prometheus看板系统 &#xff08;3&#xff09;对Prometheus界面熟悉 1.1 规划节点 主机名 主机IP 节点规划 prome-master01 10.0.1.10 服务端 prome-node01 …

java基础学习笔记1

Java编程规范 命名风格 1. 【强制】代码中的命名均不能以下划线或美元符号开始&#xff0c;也不能以下划线或美元符号结束。 反例&#xff1a;_name / __name / $name / name_ / name$ / name__ 2. 【强制】代码中的命名严禁使用拼音与英文混合的方式&#xff0c;更不允许直…