使用 HTML + JavaScript 实现文章逐句高亮朗读功能

news2025/6/8 12:33:19

在这个信息爆炸的时代,我们每天都要面对大量的文字阅读。无论是学习、工作还是个人成长,阅读都扮演着至关重要的角色。然而,在快节奏的生活中,我们往往难以找到足够的安静时间专注于阅读。本文用 HTML + JavaScript 实现了一个基于Web的语音文章朗读器,为您带来全新的阅读体验。

效果演示

image-20250603220304012

image-20250603220336133

项目核心

本项目主要包含以下核心功能:

  • 语音合成(Text-to-Speech)功能
  • 控制播放、暂停、继续和停止操作
  • 语音选择功能
  • 阅读进度保存与恢复
  • 句子级高亮显示
  • 点击任意句子直接跳转并朗读

页面结构

控制区域

包含所有操作按钮(开始、暂停、继续、停止、重置)和语音选择下拉框。

<div class="controls">
    <button id="playBtn">开始朗读</button>
    <button id="pauseBtn" disabled>暂停</button>
    <button id="resumeBtn" disabled>继续</button>
    <button id="stopBtn" disabled>停止</button>
    <select id="voiceSelect" class="voice-select"></select>
    <button id="resetBtn">重置进度</button>
</div>

文章区域

包含多个段落,每个段落由多个可交互的句子组成。

<div class="article" id="article">
    <p class="paragraph">
        <span class="sentence">在编程的世界里,学习是一个永无止境的过程。</span>
        <span class="sentence">随着技术的不断发展,我们需要不断更新自己的知识和技能。</span>
        <span class="sentence">HTML、CSS和JavaScript是构建现代网页的三大基石。</span>
    </p>
    <p class="paragraph">
        <span class="sentence">掌握这些基础技术后,你可以进一步学习各种前端框架和工具。</span>
        <span class="sentence">React、Vue和Angular是目前最流行的前端框架。</span>
        <span class="sentence">它们都采用了组件化的开发模式,提高了代码的可维护性和复用性。</span>
    </p>
    <p class="paragraph">
        <span class="sentence">除了前端技术,后端开发也是全栈工程师必须掌握的技能。</span>
        <span class="sentence">Node.js让JavaScript可以用于服务器端编程,大大扩展了JavaScript的应用范围。</span>
        <span class="sentence">数据库技术也是开发中的重要组成部分。</span>
    </p>
</div>
进度信息

显示当前阅读进度。

<div class="progress-info">
    当前进度: <span id="progressText">0/0</span>
    <div class="progress-bar-container">
        <div class="progress-bar"></div>
    </div>
</div>

核心功能实现

定义基础变量

获取DOM元素

const sentences = document.querySelectorAll('.sentence');
const playBtn = document.getElementById('playBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resumeBtn = document.getElementById('resumeBtn');
const stopBtn = document.getElementById('stopBtn');
const resetBtn = document.getElementById('resetBtn');
const voiceSelect = document.getElementById('voiceSelect');
const progressText = document.getElementById('progressText');
const progressBar = document.querySelector('.progress-bar');

定义语音合成相关变量

let speechSynthesis = window.speechSynthesis;
let voices = [];
let currentUtterance = null;
let currentSentenceIndex = 0;
let isPaused = false;
语音合成初始化

通过 window.speechSynthesis API 获取系统支持的语音列表,并填充到下拉选择框中。

function initSpeechSynthesis() {
    // 获取可用的语音列表
    voices = speechSynthesis.getVoices();

    // 填充语音选择下拉框
    voiceSelect.innerHTML = '';
    voices.forEach((voice, index) => {
        const option = document.createElement('option');
        option.value = index;
        option.textContent = `${voice.name} (${voice.lang})`;
        voiceSelect.appendChild(option);
    });

    // 尝试选择中文语音
    const chineseVoice = voices.find(voice =>{
        voice.lang.includes('zh') || voice.lang.includes('cmn')
    });
    if (chineseVoice) {
        const voiceIndex = voices.indexOf(chineseVoice);
        voiceSelect.value = voiceIndex;
    }
}
句子朗读功能
function speakSentence(index) {
    if (index >= sentences.length || index < 0) return;
    // 停止当前朗读
    if (currentUtterance) {
        speechSynthesis.cancel();
    }
    // 更新当前句子高亮
    updateHighlight(index);
    // 创建新的语音合成实例
    const selectedVoiceIndex = voiceSelect.value;
    const utterance = new SpeechSynthesisUtterance(sentences[index].textContent);
    if (voices[selectedVoiceIndex]) {
        utterance.voice = voices[selectedVoiceIndex];
    }
    utterance.rate = 0.9; // 稍微慢一点的语速
    // 朗读开始时的处理
    utterance.onstart = function() {
        sentences[index].classList.add('reading');
        playBtn.disabled = true;
        pauseBtn.disabled = false;
        resumeBtn.disabled = true;
        stopBtn.disabled = false;
    };
    // 朗读结束时的处理
    utterance.onend = function() {
        sentences[index].classList.remove('reading');
        if (!isPaused) {
            if (currentSentenceIndex >= sentences.length - 1) {
                // 朗读完成
                playBtn.disabled = false;
                pauseBtn.disabled = true;
                resumeBtn.disabled = true;
                stopBtn.disabled = true;
                updateProgressText();
                return;
            }
            currentSentenceIndex++;
            saveProgress();
            speakSentence(currentSentenceIndex);
        }
    };
    // 开始朗读
    currentUtterance = utterance;
    speechSynthesis.speak(utterance);
    updateProgressText();
}
句子高亮功能
function updateHighlight(index) {
    sentences.forEach((sentence, i) => {
        sentence.classList.remove('current');
        if (i === index) {
            sentence.classList.add('current');
            // 滚动到当前句子
            sentence.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }
    });
}
更新进度文本
function updateProgressText() {
    progressText.textContent = `${currentSentenceIndex + 1}/${sentences.length}`;
    const percentage = (currentSentenceIndex + 1) / sentences.length * 100;
    progressBar.style.width = `${percentage}%`;
}
进度保存与恢复

保存进度到本地存储

function saveProgress() {
    localStorage.setItem('readingProgress', currentSentenceIndex);
    localStorage.setItem('articleId', 'demoArticle'); 
    updateProgressText();
}

从本地存储加载进度

function loadProgress() {
    const savedArticleId = localStorage.getItem('articleId');
    if (savedArticleId === 'demoArticle') {
        const savedProgress = localStorage.getItem('readingProgress');
        if (savedProgress !== null) {
            currentSentenceIndex = parseInt(savedProgress);
            if (currentSentenceIndex >= sentences.length) {
                currentSentenceIndex = 0;
            }
            updateHighlight(currentSentenceIndex);
            updateProgressText();
        }
    }
}
点击句子朗读跳转功能
sentences.forEach((sentence, index) => {
    sentence.addEventListener('click', function() {
        currentSentenceIndex = index;
        speakSentence(currentSentenceIndex);
    });
});

扩展建议

  • 语速调节:增加语速调节滑块,让用户自定义朗读速
  • 多语言支持:自动检测文本语言并选择合适的语音引擎
  • 断句优化:改进自然语言处理逻辑,使朗读更符合口语习惯
  • 多文章支持:扩展文章管理系统,允许用户选择不同文章进行朗读

完整代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文章逐句高亮朗读</title>
    <style>
        body {
            font-family: 'Microsoft YaHei', sans-serif;
            line-height: 1.6;
            max-width: 800px;
            margin: 0 auto;
            padding: 40px 20px;
            color: #333;
            height: 100vh;
            box-sizing: border-box;
            background: linear-gradient(to bottom right, #f8f9fa, #e9ecef);
        }

        h1 {
            text-align: center;
            color: #2c3e50;
            margin-bottom: 40px;
            font-size: 2.5em;
            letter-spacing: 2px;
            position: relative;
            animation: fadeInDown 1s ease-out forwards;
        }

        @keyframes fadeInDown {
            from {
                opacity: 0;
                transform: translateY(-30px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        h1::after {
            content: '';
            display: block;
            width: 100px;
            height: 4px;
            background: linear-gradient(to right, #3498db, #2980b9);
            margin: 15px auto 0;
            border-radius: 2px;
            animation: growLine 1s ease-out forwards;
        }

        @keyframes growLine {
            from {
                width: 0;
            }
            to {
                width: 100px;
            }
        }
        .controls {
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
            border-radius: 10px;
            padding: 20px;
            background-color: #ffffffcc;
            display: flex;
            flex-direction: column;
            gap: 15px;
            margin-bottom: 30px;
        }
        .controls > div {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 15px;
        }

        button {
            padding: 10px 20px;
            background: linear-gradient(135deg, #3498db, #2980b9);
            color: white;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.3s ease-in-out;
            box-shadow: 0 4px 6px rgba(52, 152, 219, 0.3);
        }

        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 12px rgba(52, 152, 219, 0.4);
        }

        button:disabled {
            background: linear-gradient(135deg, #95a5a6, #7f8c8d);
            box-shadow: none;
            transform: none;
        }

        .article {
            font-size: 18px;
            line-height: 1.8;
            background-color: #ffffffee;
            border-radius: 10px;
            padding: 25px;
            margin-top: 30px;
            box-shadow: 0 8px 20px rgba(0, 0, 0, 0.05);
            margin-bottom: 30px;
            position: relative;
            z-index: 0
        }
        .article::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: radial-gradient(circle at top left, rgba(52, 152, 219, 0.05) 0%, transparent 100%);
            z-index: -1;
            border-radius: 10px;
        }
        .paragraph {
            margin-bottom: 20px;
        }

        .sentence {
            border-radius: 3px;
            transition: all 0.3s ease-in-out;
            cursor: pointer;
            position: relative;
            z-index: 1;
        }

        .sentence:hover {
            background-color: #f0f0f0;
        }
        .sentence::after {
            content: '';
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(255, 255, 255, 0.3);
            opacity: 0;
            z-index: -1;
            transition: opacity 0.3s ease-in-out;
        }
        .sentence:hover::after {
            opacity: 1;
        }
        .current {
            background-color: #fffde7 !important;
            font-weight: bold;
            transform: scale(1.05);
            box-shadow: 0 2px 8px rgba(255, 221, 0, 0.3);
        }
        .progress-info {
            text-align: center;
            margin-top: 20px;
            font-size: 14px;
            color: #7f8c8d;
        }

        select {
            padding: 8px;
            border-radius: 4px;
            border: 1px solid #bdc3c7;
            font-size: 16px;
        }

        .voice-select {
            min-width: 220px;
            padding: 10px 12px;
            border-radius: 25px;
            border: 1px solid #bdc3c7;
            font-size: 16px;
            background-color: #f8f9fa;
            transition: all 0.3s ease-in-out;
            appearance: none;
            background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'%3E%3Cpath fill='%23555' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
            background-repeat: no-repeat;
            background-position: right 15px center;
            background-size: 12px;
            display: block;
            margin: 0 auto;
        }

        .voice-select:focus {
            outline: none;
            border-color: #3498db;
            box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
        }

        .progress-info {
            text-align: center;
            margin-top: 30px;
            font-size: 14px;
            color: #7f8c8d;
            position: relative;
            height: 30px;
        }

        .progress-bar-container {
            width: 100%;
            height: 6px;
            background-color: #ecf0f1;
            border-radius: 3px;
            overflow: hidden;
            margin: 10px 0;
        }

        .progress-bar {
            height: 100%;
            width: 0;
            background: linear-gradient(to right, #3498db, #2980b9);
            transition: width 0.3s ease-in-out;
        }
    </style>
</head>
<body>
<h1>文章逐句高亮朗读</h1>

<div class="controls">
    <div>
        <button id="playBtn">开始朗读</button>
        <button id="pauseBtn" disabled>暂停</button>
        <button id="resumeBtn" disabled>继续</button>
        <button id="stopBtn" disabled>停止</button>
        <button id="resetBtn">重置进度</button>
    </div>
    <select id="voiceSelect" class="voice-select"></select>
</div>

<div class="article" id="article">
    <p class="paragraph">
        <span class="sentence">在编程的世界里,学习是一个永无止境的过程。</span>
        <span class="sentence">随着技术的不断发展,我们需要不断更新自己的知识和技能。</span>
        <span class="sentence">HTML、CSS和JavaScript是构建现代网页的三大基石。</span>
    </p>
    <p class="paragraph">
        <span class="sentence">掌握这些基础技术后,你可以进一步学习各种前端框架和工具。</span>
        <span class="sentence">React、Vue和Angular是目前最流行的前端框架。</span>
        <span class="sentence">它们都采用了组件化的开发模式,提高了代码的可维护性和复用性。</span>
    </p>
    <p class="paragraph">
        <span class="sentence">除了前端技术,后端开发也是全栈工程师必须掌握的技能。</span>
        <span class="sentence">Node.js让JavaScript可以用于服务器端编程,大大扩展了JavaScript的应用范围。</span>
        <span class="sentence">数据库技术也是开发中的重要组成部分。</span>
    </p>
</div>

<div class="progress-info">
    当前进度: <span id="progressText">0/0</span>
    <div class="progress-bar-container">
        <div class="progress-bar"></div>
    </div>
</div>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        // 获取DOM元素
        const sentences = document.querySelectorAll('.sentence');
        const playBtn = document.getElementById('playBtn');
        const pauseBtn = document.getElementById('pauseBtn');
        const resumeBtn = document.getElementById('resumeBtn');
        const stopBtn = document.getElementById('stopBtn');
        const resetBtn = document.getElementById('resetBtn');
        const voiceSelect = document.getElementById('voiceSelect');
        const progressText = document.getElementById('progressText');
        const progressBar = document.querySelector('.progress-bar');

        // 语音合成相关变量
        let speechSynthesis = window.speechSynthesis;
        let voices = [];
        let currentUtterance = null;
        let currentSentenceIndex = 0;
        let isPaused = false;

        // 从本地存储加载进度
        loadProgress();

        // 初始化语音合成
        function initSpeechSynthesis() {
            // 获取可用的语音列表
            voices = speechSynthesis.getVoices();

            // 填充语音选择下拉框
            voiceSelect.innerHTML = '';
            voices.forEach((voice, index) => {
                const option = document.createElement('option');
                option.value = index;
                option.textContent = `${voice.name} (${voice.lang})`;
                voiceSelect.appendChild(option);
            });

            // 尝试选择中文语音
            const chineseVoice = voices.find(voice =>{
                voice.lang.includes('zh') || voice.lang.includes('cmn')
            });
            if (chineseVoice) {
                const voiceIndex = voices.indexOf(chineseVoice);
                voiceSelect.value = voiceIndex;
            }
        }

        // 语音列表加载可能需要时间
        speechSynthesis.onvoiceschanged = initSpeechSynthesis;
        initSpeechSynthesis();

        // 朗读指定句子
        function speakSentence(index) {
            if (index >= sentences.length || index < 0) return;
            // 停止当前朗读
            if (currentUtterance) {
                speechSynthesis.cancel();
            }
            // 更新当前句子高亮
            updateHighlight(index);
            // 创建新的语音合成实例
            const selectedVoiceIndex = voiceSelect.value;
            const utterance = new SpeechSynthesisUtterance(sentences[index].textContent);
            if (voices[selectedVoiceIndex]) {
                utterance.voice = voices[selectedVoiceIndex];
            }
            utterance.rate = 0.9; // 稍微慢一点的语速
            // 朗读开始时的处理
            utterance.onstart = function() {
                sentences[index].classList.add('reading');
                playBtn.disabled = true;
                pauseBtn.disabled = false;
                resumeBtn.disabled = true;
                stopBtn.disabled = false;
            };
            // 朗读结束时的处理
            utterance.onend = function() {
                sentences[index].classList.remove('reading');
                if (!isPaused) {
                    if (currentSentenceIndex >= sentences.length - 1) {
                        // 朗读完成
                        playBtn.disabled = false;
                        pauseBtn.disabled = true;
                        resumeBtn.disabled = true;
                        stopBtn.disabled = true;
                        updateProgressText();
                        return;
                    }
                    currentSentenceIndex++;
                    saveProgress();
                    speakSentence(currentSentenceIndex);
                }
            };
            // 开始朗读
            currentUtterance = utterance;
            speechSynthesis.speak(utterance);
            updateProgressText();
        }

        // 更新句子高亮
        function updateHighlight(index) {
            sentences.forEach((sentence, i) => {
                sentence.classList.remove('current');
                if (i === index) {
                    sentence.classList.add('current');
                    // 滚动到当前句子
                    sentence.scrollIntoView({ behavior: 'smooth', block: 'center' });
                }
            });
        }

        // 更新进度文本
        function updateProgressText() {
            progressText.textContent = `${currentSentenceIndex + 1}/${sentences.length}`;
            const percentage = (currentSentenceIndex + 1) / sentences.length * 100;
            progressBar.style.width = `${percentage}%`;
        }

        // 保存进度到本地存储
        function saveProgress() {
            localStorage.setItem('readingProgress', currentSentenceIndex);
            localStorage.setItem('articleId', 'demoArticle'); // 在实际应用中可以使用文章ID
            updateProgressText();
        }

        // 从本地存储加载进度
        function loadProgress() {
            const savedArticleId = localStorage.getItem('articleId');
            if (savedArticleId === 'demoArticle') {
                const savedProgress = localStorage.getItem('readingProgress');
                if (savedProgress !== null) {
                    currentSentenceIndex = parseInt(savedProgress);
                    if (currentSentenceIndex >= sentences.length) {
                        currentSentenceIndex = 0;
                    }
                    updateHighlight(currentSentenceIndex);
                    updateProgressText();
                }
            }
        }

        // 事件监听器
        playBtn.addEventListener('click', function() {
            currentSentenceIndex = 0;
            speakSentence(currentSentenceIndex);
        });

        pauseBtn.addEventListener('click', function() {
            if (speechSynthesis.speaking && !isPaused) {
                speechSynthesis.pause();
                isPaused = true;
                pauseBtn.disabled = true;
                resumeBtn.disabled = false;
            }
        });

        resumeBtn.addEventListener('click', function() {
            if (isPaused) {
                speechSynthesis.resume();
                isPaused = false;
                pauseBtn.disabled = false;
                resumeBtn.disabled = true;
            }
        });

        stopBtn.addEventListener('click', function() {
            speechSynthesis.cancel();
            isPaused = false;
            playBtn.disabled = false;
            pauseBtn.disabled = true;
            resumeBtn.disabled = true;
            stopBtn.disabled = true;

            // 移除所有朗读样式
            sentences.forEach(sentence => {
                sentence.classList.remove('reading');
            });
        });

        resetBtn.addEventListener('click', function() {
            localStorage.removeItem('readingProgress');
            localStorage.removeItem('articleId');
            currentSentenceIndex = 0;
            updateHighlight(currentSentenceIndex);
            updateProgressText();
        });

        // 点击句子跳转到该句子并朗读
        sentences.forEach((sentence, index) => {
            sentence.addEventListener('click', function() {
                currentSentenceIndex = index;
                speakSentence(currentSentenceIndex);
            });
        });
    });
</script>
</body>
</html>

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

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

相关文章

双碳时代,能源调度的难题正从“发电侧”转向“企业侧”

安科瑞刘鸿鹏 摘要 在“双碳”战略和能源结构转型的大背景下&#xff0c;企业储能电站逐步成为提升能源利用效率、增强用能韧性的重要手段。随着系统规模扩大与运行复杂度提升&#xff0c;如何对光伏、储能、负荷等流进行实时调控&#xff0c;成为智慧用能的关键。ACCU100微…

3. 简述node.js特性与底层原理

&#x1f63a;&#x1f63a;&#x1f63a; 一、Node.js 底层原理&#xff08;简化版&#xff09; Node.js 是一个 基于 Chrome V8 引擎构建的 JavaScript 运行时&#xff0c;底层核心由几部分组成&#xff1a; 组成部分简要说明 1.V8 引擎 将 JS 编译成机器码执行&#xff0…

OpenCV CUDA模块图像处理------创建一个模板匹配(Template Matching)对象函数createTemplateMatching()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 创建一个用于在 GPU 上执行模板匹配的 TemplateMatching 对象。 该函数返回一个指向 TemplateMatching 的智能指针&#xff08;Ptr&#xff09;…

【Kubernetes】K8s 之 ETCD - 恢复备份

ETCD 是一个高可用的分布式键值存储&#xff0c;常用于存储配置信息和服务发现等。当系统出现故障或数据损坏时&#xff0c;能够快速恢复成先前的状态是维护系统稳定性的关键。ETCD 提供了备份和恢复功能&#xff0c;以确保数据持久性和可靠性&#xff0c;一起来看看如何操作吧…

RabbitMQ 学习

MQ 的相关概念 什么是 MQ MQ&#xff08;message queue&#xff09;&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是 message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用于上下游传递消息。…

如何轻松、安全地管理密码(新手指南)

很多人会为所有账户使用相同、易记的密码&#xff0c;而且常常多年不换。虽然这样方便记忆&#xff0c;但安全性非常低。 您可能听说过一些大型网站的信息泄露事件&#xff0c;同样的风险也可能存在于您的WordPress网站中。如果有不法分子获取了访问权限&#xff0c;您的网站和…

AWS App Mesh实战:构建可观测、安全的微服务通信解决方案

摘要&#xff1a;本文详解如何利用AWS App Mesh统一管理微服务间通信&#xff0c;实现精细化流量控制、端到端可观测性与安全通信&#xff0c;提升云原生应用稳定性。 一、什么是AWS App Mesh&#xff1f; AWS App Mesh 是一种服务网格&#xff08;Service Mesh&#xff09;解…

9.axios底层原理,和promise的对比(2)

&#x1f63a;&#x1f63a;&#x1f63a; 和promise的对比 完全可以直接使用 Promise 来发 HTTP 请求&#xff0c;比如用原生 fetch Promise 就可以实现网络请求功能&#x1f447; ✅ 用 Promise fetch 的写法&#xff08;原生&#xff09; fetch(‘https://api.example.c…

用HTML5 Canvas打造交互式心形粒子动画:从基础到优化实战

用HTML5 Canvas打造交互式心形粒子动画&#xff1a;从基础到优化实战 引言 在Web交互设计中&#xff0c;粒子动画因其动态美感和视觉吸引力被广泛应用于节日特效、情感化界面等场景。本文将通过实战案例&#xff0c;详细讲解如何使用HTML5 Canvas和JavaScript实现一个「心之律…

【软件工具】批量OCR指定区域图片自动识别内容重命名软件使用教程及注意事项

批量OCR指定区域图片自动识别内容重命名软件使用教程及注意事项 1、操作步骤1-5&#xff1a; 安装与启动&#xff1a;安装成功后&#xff0c;在桌面或开始菜单找到软件图标&#xff0c;双击启动。 导入图片&#xff1a;进入软件主界面&#xff0c;点击 “导入图片” 按钮&a…

数据通信与计算机网络——数字传输

主要内容 数字到数字转换 线路编码 线路编码方案 块编码 扰动 模拟到数字转换 脉冲码调制&#xff08;PCM&#xff09; Delta调制&#xff08;DM&#xff09; 传输模式 并行传输 串行传输 一、数字到数字转换 将数字数据转换为数字信号涉及三种技术&#xff1a; 线…

黄柏基因组-小檗碱生物合成的趋同进化-文献精读142

Convergent evolution of berberine biosynthesis 小檗碱生物合成的趋同进化 摘要 小檗碱是一种有效的抗菌和抗糖尿病生物碱&#xff0c;主要从不同植物谱系中提取&#xff0c;特别是从小檗属&#xff08;毛茛目&#xff0c;早期分支的真双子叶植物&#xff09;和黄柏属&…

前端杂货铺——TodoList

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

Spring Boot SSE流式输出+AI消息持久化升级实践:从粗暴到优雅的跃迁

在 AI 应用落地过程中&#xff0c;我们常常需要将用户和 AI 的对话以“完整上下文”的形式持久化到数据库中。但当 AI 回复非常长&#xff0c;甚至接近上万字时&#xff0c;传统的单条消息保存机制就会出问题。 在本篇文章中&#xff0c;我将深入讲解一次实际项目中对 对话持久…

Model Context Protocol (MCP) 是一个前沿框架

微软发布了 Model Context Protocol (MCP) 课程&#xff1a;mcp-for-beginners。 Model Context Protocol (MCP) 是一个前沿框架&#xff0c;涵盖 C#、Java、JavaScript、TypeScript 和 Python 等主流编程语言&#xff0c;规范 AI 模型与客户端应用之间的交互。 MCP 课程结构 …

内容力重塑品牌增长:开源AI大模型驱动下的智能名片与S2B2C商城赋能抖音生态种草范式

摘要&#xff1a;内容力已成为抖音生态中品牌差异化竞争的核心能力&#xff0c;通过有价值、强共鸣的内容实现产品"种草"与转化闭环。本文基于"开源AI大模型AI智能名片S2B2C商城小程序源码"技术架构&#xff0c;提出"技术赋能内容"的新型种草范式…

手机号在网状态查询接口如何用PHP实现调用?

一、什么是手机号在网状态查询接口 通过精准探测手机号的状态&#xff0c;帮助平台减少此类问题的发生&#xff0c;提供更个性化的服务或进行地域性营销 二、应用场景 1. 金融风控 通过运营商在网态查询接口&#xff0c;金融机构可以核验贷款申请人的手机状态&#xff0c;拦…

【Java微服务组件】分布式协调P4-一文打通Redisson:从API实战到分布式锁核心源码剖析

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录 引言Redisson基本信息Redisson网站 Redisson应用…

一个简单的德劳内三角剖分实现

德劳内&#xff08;Delaunay&#xff09;三角剖分是一种经典的将点集进行三角网格化预处理的手段&#xff0c;在NavMesh、随机地牢生成等场景下都有应用。 具体内容百度一大堆&#xff0c;就不介绍了。 比较知名的算法是Bowyer-Watson算法&#xff0c;也就是逐点插入法。 下雨闲…

C#子线程更新主线程UI及委托回调使用示例

1.声明线程方法 2.线程中传入对象 3.声明委托与使用 声明委托对象 委托作为参数传入方法 4.在线程中传入委托 5.调用传入的委托