Chainlit集成Dashscope实现语音交互网页对话AI应用

前言

本篇文章讲解和实战,如何使用Chainlit集成Dashscope实现语音交互网页对话AI应用。实现方案是对接阿里云提供的语音识别SenseVoice大模型接口和语音合成CosyVoice大模型接口使用。针对SenseVoice大模型和CosyVoice大模型,阿里巴巴在github提供的有开源代码,也可以自己本地部署SenseVoice大模型和CosyVoice大模型接口服务。特别提及一下,阿里云上还有另外一套,语音识别和语音合成的接口,Paraformer语音识别和Sambert语音合成,相比之下个人觉得不如SenseVoice大模型和CosyVoice大模型。中间踩了一个坑,浪费我好几天研究,就是阿里云平台上Paraformer语音识别的接口,可以直接传文件路径或者文件流而SenseVoice大模型的接口。所以我一直中意用Paraformer语音识别的接口,但是识别的语音文件,老是识别不出来,一开始我觉得是哪些参数没传对,或者是我麦克风生成语音文件有问题,老是语音识别不出来,后来看了一些文档,支持的音频采样率,只有16khz的,而我音频格式不是。所以就换成SenseVoice大模型的接口,只接受文件的url不支持本地文件直接上传,这个接口需要需要将音频文件先上传到oss等生成一个可以访问文件的url。一开始我觉得会很慢,但是实测起来,速度还行。

Dashscope

DashScope 是阿里云推出的一款模型服务产品,旨在简化人工智能(AI)模型的应用与部署过程。它针对主流的AI大模型进行了标准化封装,提供了API接口,使得开发者能够轻松调用这些模型,并进行推理、训练、微调等操作。DashScope 的主要特点包括:

  1. 丰富的模型选择:DashScope 提供了多种类型的模型,涵盖自然语言处理、计算机视觉等多个领域,满足不同场景下的需求。
  2. 简便的集成方式:通过Python/Java SDK或HTTP请求,开发者可以方便地将AI模型集成到自己的应用程序中。
  3. 开箱即用:无需深入了解模型内部机制,用户可以直接调用API完成复杂的AI任务。
  4. 高效的性能优化:在模型推理优化、高效微调训练等方面积累了大量的技术实力,提升了模型使用的效率和效果。
  5. 灵活的弹性底座:改善了模型推理、微调效率低及规模响应慢的问题,提供了更加灵活的服务支持。
  6. 成本经济:提供了合理的计费模式,包括免费试用额度,帮助开发者降低成本。

此外,DashScope 还支持特定领域的高级功能,如语音合成、图像识别等,适用于广泛的行业和应用场景。通过DashScope,开发者可以获得一个强大的工具集来加速AI项目的开发和部署。

语音识别SenseVoice大模型

阿里巴巴的语音识别大模型 SenseVoice 是其在语音技术领域的一项重要成果,主要特点和能力如下:

  1. 高精度多语言语音识别:SenseVoice 能够提供高精度的语音转文字服务,支持多种语言的识别,适用于跨国界、跨文化的交流场景。

  2. 情感辨识:除了传统的语音识别外,SenseVoice 还能够识别说话者的情感状态,如高兴、悲伤、愤怒等,这对于构建更加人性化的对话系统非常有用。

  3. 音频事件检测:SenseVoice 可以检测音频中的特定事件,例如掌声、笑声、咳嗽等,这种能力在媒体分析、智能监控等领域具有广泛应用前景。

  4. 快速适应不同场景:通过先进的模型训练技术和算法优化,SenseVoice 能够快速适应不同的环境和使用场景,即使是在嘈杂的环境中也能保持较高的识别精度。

  5. 支持语音克隆:SenseVoice 具备语音克隆的能力,可以通过少量样本学习特定人的声音特征,进而生成相似的声音输出,这项技术在个性化语音助手、虚拟主播等领域有着广阔的应用空间。

  6. 开源共享:作为阿里通义实验室的一部分,SenseVoice 已经被开源,这促进了学术界和工业界之间的技术交流和进步,也为更多开发者提供了研究和应用的机会。

  7. 强大的技术支持:依托阿里巴巴深厚的技术积累和丰富的应用场景,SenseVoice 在性能、稳定性等方面得到了充分保障。

综上所述,SenseVoice 是一款集成了多项先进功能和技术的语音识别大模型,旨在通过提供高质量的语音处理服务,推动人机交互体验的进一步提升。

语音合成CosyVoice大模型

CosyVoice 是阿里通义实验室开发的一款先进的多语言语音合成大模型,旨在通过融合大规模预训练语言模型和深度学习技术,提供高质量、自然流畅的语音合成服务。以下是 CosyVoice 的主要特点和优势:

  1. 多语言支持:CosyVoice 支持包括中文、英文、日文、粤语和韩语在内的多种语言的语音合成,满足全球用户的多样化需求。

  2. 自然逼真的语音质量:通过超过15万小时的多语言语音数据训练,CosyVoice 能够生成几乎与真人无异的语音,无论是发音清晰度还是情感表达都达到了很高的水平。

  3. 快速音色克隆:CosyVoice 可以在短短几秒钟内从提供的音频样本中学习并复制特定的音色特性,使用户能够轻松创建个性化的语音内容。

  4. 情感和韵律控制:CosyVoice 允许对合成语音的情感色彩和节奏进行细致调整,从而更好地适应不同的应用场景和内容需求。

  5. 开源开放:CosyVoice 已经对外开源,不仅为开发者提供了使用这一先进技术的机会,同时也促进了学术界和工业界之间的技术交流和发展。

  6. 灵活的部署选项:CosyVoice 提供了从云端服务到本地部署的多种解决方案,用户可以根据自身需求选择最适合的部署方式。

  7. 全面的技术文档和支持:为了帮助用户更好地理解和使用 CosyVoice,官方提供了详细的使用教程和技术文档,以及持续的技术支持。

总之,CosyVoice 是一个功能强大、使用灵活的语音合成工具,它不仅能够为个人用户提供高质量的语音内容创作能力,同时也为企业和开发者提供了实现语音相关应用和服务的重要手段。

快速上手

创建一个文件,例如“chainlit_chat”

mkdir chainlit_chat

进入 chainlit_chat文件夹下,执行命令创建python 虚拟环境空间(需要提前安装好python sdkChainlit 需要python>=3.8。,具体操作,由于文章长度问题就不在叙述,自行百度),命令如下:

python -m venv .venv
  • 这一步是避免python第三方库冲突,省事版可以跳过
  • .venv是创建的虚拟空间文件夹可以自定义

接下来激活你创建虚拟空间,命令如下:

#linux or mac
source .venv/bin/activate
#windows
.venv\Scripts\activate

在项目根目录下创建requirements.txt,内容如下:

chainlit
dashscope

执行以下命令安装依赖:

pip install -r .\requirements.txt
  • 安装后,项目根目录下会多出.chainlit.files文件夹和chainlit.md文件

代码创建

只使用通义千问的DashScope模型服务灵积的接口

在项目根目录下创建.env环境变量,配置如下:

DASHSCOPE_API_KEY="sk-api_key"
  • DASHSCOPE_API_KEY 是阿里dashscope的服务的APIkey,代码中使用DashScope的sdk实现,所以不需要配置base_url。默认就是阿里的base_url。
  • 阿里模型接口地址 https://dashscope.console.aliyun.com/model
  • DashScope模型服务灵积文档地址 https://help.aliyun.com/zh/dashscope/

在项目根目录下创建app.py文件,代码如下:

import re
import tempfile
import time
from http import HTTPStatus
from io import BytesIOimport chainlit as cl
import dashscope.file
import requests
from chainlit.element import ElementBased
from dashscope.audio.tts_v2 import SpeechSynthesizer
from dashscope.common.constants import FilePurposeasync def text_to_speech(text: str):synthesizer = SpeechSynthesizer(model='cosyvoice-v1', voice='longxiaochun')audio = synthesizer.call(text)return "", audioasync def speech_to_text(audio_file):result = dashscope.Files.upload(file_path=audio_file,purpose=FilePurpose.assistants)file_id = result.output['uploaded_files'][0]['file_id']file_res = dashscope.Files.get(file_id)task_response = dashscope.audio.asr.Transcription.async_call(model='sensevoice-v1',file_urls=[file_res.output['url']],language_hints=['zh', 'en'],)transcribe_response = dashscope.audio.asr.Transcription.wait(task=task_response.output.task_id)if transcribe_response.status_code == HTTPStatus.OK:transcription_url = transcribe_response.output["results"][0]["transcription_url"]# 发送GET请求response = requests.get(transcription_url)# 检查请求是否成功if response.status_code == 200:# 使用内置的json()方法将响应体解析为字典data = response.json()print(data)print(data['transcripts'][0]['text'])text = data['transcripts'][0]['text']# 使用正则表达式提取标签之间的文本pattern = r'<\|Speech\|>(.*?)<\|/Speech\|>'match = re.search(pattern, text, re.DOTALL)if match:text = match.group(1).strip()else:text = ''return textelse:print(f"Failed to retrieve data: {response.status_code}")return "fail"@cl.step(type="tool", name="AI问答")
async def generate_text_answer(message: cl.Message):start_time = time.time()msg = cl.Message(content="")await msg.send()messages = [{'role': 'system', 'content': 'You are a helpful assistant.'},{'role': 'user', 'content': message.content}]print('content', message.content)stream = dashscope.Generation.call(model="qwen-plus",messages=messages,result_format='message',stream=True,incremental_output=True)print(f"代码执行时间: {time.time() - start_time} 秒")for part in stream:if token := part.output.choices[0].message.content or "":await msg.stream_token(token)return msg@cl.on_message
async def on_message(message: cl.Message):msg = await generate_text_answer(message)await msg.update()@cl.on_audio_chunk
async def on_audio_chunk(chunk: cl.AudioChunk):if chunk.isStart:buffer = BytesIO()buffer.name = f"input_audio.{chunk.mimeType.split('/')[1]}"# Initialize the session for a new audio streamcl.user_session.set("audio_buffer", buffer)cl.user_session.set("audio_mime_type", chunk.mimeType)# For now, write the chunks to a buffer and transcribe the whole audio at the endcl.user_session.get("audio_buffer").write(chunk.data)@cl.on_audio_end
async def on_audio_end(elements: list[ElementBased]):# Get the audio buffer from the sessionaudio_buffer: BytesIO = cl.user_session.get("audio_buffer")audio_mime_type: str = cl.user_session.get("audio_mime_type")audio_buffer.seek(0)  # 将文件指针移到开头# 使用pydub处理音频try:with tempfile.NamedTemporaryFile(delete=False, suffix=".webm") as tmpFile:tmpFile.write(audio_buffer.read())tmpFile_path = tmpFile.nameexcept Exception as e:print(f"Error processing audio: {e}")print('tmpFile_path', tmpFile_path)transcription = await speech_to_text(tmpFile_path)input_audio_el = cl.Audio(mime=audio_mime_type, path=tmpFile_path, name="",)message = await cl.Message(author="You",type="user_message",content=transcription,elements=[input_audio_el, *elements]).send()print('transcription', transcription)msg = await generate_text_answer(message)output_name, output_audio = await text_to_speech(msg.content)output_audio_el = cl.Audio(name=output_name, auto_play=True, mime='audio/wav', content=output_audio)msg.elements = [output_audio_el]await msg.update()
  • 这里我使用的国内阿里云的DashScope sdk 服务。
  • 如果要保存用户聊天记录,这里生成语音文件,如果要保存起来,本地或者oss等。
  • 代码实现的是,语音问答的时候会回复文字和语音,语音设置的默认播放,文字问答的时候,只回复文字。
  • 代码还有一些不完善的地方,比如异常的处理还不完善,部署生产的时候记得完善

代码解读

这段代码是一个基于 chainlit 框架的聊天机器人应用,它结合了阿里云的多个服务,包括语音合成(TTS)、语音识别(ASR)和文本生成(Text Generation),实现了从语音输入到文本处理再到语音输出的完整流程。下面是各个部分的功能解读:

1. 引入必要的模块

import re
import tempfile
import time
from http import HTTPStatus
from io import BytesIOimport chainlit as cl
import dashscope.file
import requests
from chainlit.element import ElementBased
from dashscope.audio.tts_v2 import SpeechSynthesizer
from dashscope.common.constants import FilePurpose
  • 导入了用于处理字符串、文件操作、时间测量、HTTP状态码、字节流处理、网络请求、链式元素以及阿里云 DashScope 相关模块。

2. 定义 text_to_speech 函数

async def text_to_speech(text: str):synthesizer = SpeechSynthesizer(model='cosyvoice-v1', voice='longxiaochun')audio = synthesizer.call(text)return "", audio
  • 使用 SpeechSynthesizer 对象调用语音合成功能,将文本转换为语音。这里使用的是 CosyVoice 模型和特定的声音(longxiaochun)。

3. 定义 speech_to_text 函数

async def speech_to_text(audio_file):# 上传音频文件至阿里云result = dashscope.Files.upload(file_path=audio_file, purpose=FilePurpose.assistants)file_id = result.output['uploaded_files'][0]['file_id']file_res = dashscope.Files.get(file_id)# 调用语音转文字服务task_response = dashscope.audio.asr.Transcription.async_call(model='sensevoice-v1',file_urls=[file_res.output['url']],language_hints=['zh', 'en'],)transcribe_response = dashscope.audio.asr.Transcription.wait(task=task_response.output.task_id)if transcribe_response.status_code == HTTPStatus.OK:transcription_url = transcribe_response.output["results"][0]["transcription_url"]response = requests.get(transcription_url)if response.status_code == 200:data = response.json()text = data['transcripts'][0]['text']# 使用正则表达式提取标签之间的文本pattern = r'<\|Speech\|>(.*?)<\|/Speech\|>'match = re.search(pattern, text, re.DOTALL)if match:text = match.group(1).strip()else:text = ''return textelse:print(f"Failed to retrieve data: {response.status_code}")return "fail"
  • 此函数负责将音频文件上传到阿里云,并调用语音识别服务将音频转换为文本。如果识别成功,则返回识别后的文本;否则返回 "fail"

4. 定义 generate_text_answer 函数

@cl.step(type="tool", name="AI问答")
async def generate_text_answer(message: cl.Message):start_time = time.time()msg = cl.Message(content="")await msg.send()messages = [{'role': 'system', 'content': 'You are a helpful assistant.'},{'role': 'user', 'content': message.content}]stream = dashscope.Generation.call(model="qwen-plus",messages=messages,result_format='message',stream=True,incremental_output=True)for part in stream:if token := part.output.choices[0].message.content or "":await msg.stream_token(token)return msg
  • 使用阿里云的文本生成模型 qwen-plus 根据用户的输入生成回复。此函数会将生成的每个片段逐步发送给用户,以实现流式响应。

5. 定义消息处理函数

@cl.on_message
async def on_message(message: cl.Message):msg = await generate_text_answer(message)await msg.update()
  • 当接收到用户的消息时,调用 generate_text_answer 函数生成回复,并更新消息对象。

6. 处理音频数据

@cl.on_audio_chunk
async def on_audio_chunk(chunk: cl.AudioChunk):if chunk.isStart:buffer = BytesIO()buffer.name = f"input_audio.{chunk.mimeType.split('/')[1]}"cl.user_session.set("audio_buffer", buffer)cl.user_session.set("audio_mime_type", chunk.mimeType)cl.user_session.get("audio_buffer").write(chunk.data)
  • 当接收到音频数据块时,将其写入内存中的缓冲区。如果是音频流的开始,则初始化缓冲区。

7. 结束音频处理

@cl.on_audio_end
async def on_audio_end(elements: list[ElementBased]):audio_buffer: BytesIO = cl.user_session.get("audio_buffer")audio_mime_type: str = cl.user_session.get("audio_mime_type")audio_buffer.seek(0)with tempfile.NamedTemporaryFile(delete=False, suffix=".webm") as tmpFile:tmpFile.write(audio_buffer.read())tmpFile_path = tmpFile.nametranscription = await speech_to_text(tmpFile_path)input_audio_el = cl.Audio(mime=audio_mime_type, path=tmpFile_path, name="")message = await cl.Message(author="You",type="user_message",content=transcription,elements=[input_audio_el, *elements]).send()msg = await generate_text_answer(message)output_name, output_audio = await text_to_speech(msg.content)output_audio_el = cl.Audio(name=output_name, auto_play=True, mime='audio/wav', content=output_audio)msg.elements = [output_audio_el]await msg.update()
  • 当音频流结束时,将所有收集到的音频数据保存到临时文件中,并调用 speech_to_text 函数进行语音识别。然后根据识别结果生成回复,并将回复转换为语音发送给用户。

总结

这个应用实现了从接收用户语音输入,到自动转录为文本,再到根据文本生成回复,最后将回复转换为语音输出的全过程。通过阿里云的多个服务,它能够提供流畅的交互体验。

运行应用程序

要启动 Chainlit 应用程序,请打开终端并导航到包含的目录app.py。然后运行以下命令:

 chainlit run app.py -w   
  • -w标志告知 Chainlit 启用自动重新加载,因此您无需在每次更改应用程序时重新启动服务器。您的聊天机器人 UI 现在应该可以通过http://localhost:8000访问。
  • 自定义端口可以追加--port 80

启动后界面如下:

在这里插入图片描述

相关文章推荐

《Chainlit快速实现AI对话应用的界面定制化教程》
《Chainlit接入FastGpt接口快速实现自定义用户聊天界面》
《使用 Xinference 部署本地模型》
《Fastgpt接入Whisper本地模型实现语音输入》
《Fastgpt部署和接入使用重排模型bge-reranker》
《Fastgpt部署接入 M3E和chatglm2-m3e文本向量模型》
《Fastgpt 无法启动或启动后无法正常使用的讨论(启动失败、用户未注册等问题这里)》
《vllm推理服务兼容openai服务API》
《vLLM模型推理引擎参数大全》
《解决vllm推理框架内在开启多显卡时报错问题》
《Ollama 在本地快速部署大型语言模型,可进行定制并创建属于您自己的模型》

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构之红黑树实现(全)

一、红黑树 红黑树是一种自平衡的二叉搜索树&#xff0c;它通过约束节点的颜色和结构来保持平衡。红黑树是由 Rudolf Bayer 在1972年发明的&#xff0c;被认为是一种优秀的平衡树结构&#xff0c;广泛应用于各种数据结构和算法中。 1.红黑树的性质 1. 每个结点是红的或者黑的…

Mac 备忘录妙用

之前使用 Windows 的过程中&#xff0c;最痛苦的事是没有一款可以满足我快速进行记录的应用 基本都得先打开该笔记软件&#xff0c;然后创建新笔记&#xff0c;最后才能输入&#xff0c;这么多步骤太麻烦了 在切换到 MacOS 之后&#xff0c;让我惊喜的就是自带的备忘录&#…

android——自定义控件(不停变化的textview、开关switch、动画效果的打勾)

一、从开始数字到结束数字&#xff0c;不断变化 import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.content.Context; import android.util.AttributeSet; import android.view.animation.AccelerateDecelerateInterpolator;i…

设计模式-原型模式(克隆、Clone、Prototype)

原型模式&#xff08;克隆、Clone、Prototype&#xff09;是一种创建型设计模式&#xff0c; 使你能够复制已有对象&#xff0c; 而又无需使代码依赖它们所属的类。 问题 譬如美国研制了一种特效药&#xff0c;而且还在专利保护器内&#xff0c;而印度制药公司看中了&#xff0…

2024 第一次周赛

A: 题目大意 骑士每连续 i 天每天会得到 i 个金币&#xff0c;&#xff08;i 1&#xff0c; 2&#xff0c; 3 &#xff0c; …&#xff09;,那么展开看每一天可以得到的金币数&#xff1a;1 2 2 3 3 3 4 4 4 5 5 5 5 5 … 可以发现就是1个1 &#xff0c;2个2, 3个3…,那么我…

Flutter 3.24 发布:GPU模块及多视图嵌入功能

Flutter 3.24 发布&#xff1a;GPU模块及多视图嵌入功能 Flutter 3.24 带来了许多新功能和改进&#xff0c;让开发应用程序变得更加容易和有趣。这个版本重点展示了 Flutter GPU 的预览功能&#xff0c;让应用程序可以直接使用高级图形和 3D 场景功能。 此外&#xff0c;网页…

win软件 超强的本地视频 图片去水印 动态水印!

AI视频图片去水印 HitPaw Watermark Remover 电脑软件&#xff0c;内涵安装教程&#xff0c;以后看到有水印的视频不怕啦&#xff0c;用这个就行了&#xff0c;可以去除动态水印&#xff01; 【下载】 https://pan.quark.cn/s/1ba6f088f0b2 【应用名称】:HitPaw Watermark R…

ARIMA 模型初体验 —— 预测股票数据

第 1 步&#xff0c;从 twelvedata 上获取苹果 11 号 15:30 到 16:00 的 OHLC、成交量 数据。 第 2 步&#xff0c;编写 Python 代码&#xff08;实际上可以用 R 语言&#xff0c;R 语言从语言的级别对分析预测提供了支持&#xff0c;而 Python 需要第三方库&#xff09;。 …

C++ day04(友元 friend、运算符重载、String字符串)

目录 【1】友元 friend 1》概念 2》友元函数 3》友元类 4》友元成员函数 【2】运算符重载 1》概念 2》友元函数运算符重载 ​编辑 3》成员函数运算符重载 4》赋值运算符与类型转换运算符重载 5》注意事项 【3】String 字符串类 【1】友元 friend 1》概念 定义&#x…

BUUCTF-greatescape1

发现有ftp包和tcp包居多 下载解压是个流量包&#xff0c;使用wiresharh打开&#xff0c;CTRLF&#xff0c;按下图搜索ftp tcp18流发现ssc.key 传送&#xff0c;在19流发现key内容 复制保存为ssc.key, 加载key解密tls&#xff0c;再追踪tls流可得flag INS{OkThatWasWay2Easy} …

多元线性回归:机器学习中的经典模型探讨

引言 多元线性回归是统计学和机器学习中广泛应用的一种回归分析方法。它通过分析多个自变量与因变量之间的关系&#xff0c;帮助我们理解和预测数据的行为。本文将深入探讨多元线性回归的理论背景、数学原理、模型构建、技术细节及其实际应用。 一、多元线性回归的背景与发展…

基于Java的旅游网站管理系统—计算机毕业设计源码39235

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对旅游网站等问题&#xff0c;对旅游网站进行…

一区大黄蜂!人工蜂群算法优化!ABC-CNN-LSTM-MATT多特征分类预测

一区大黄蜂&#xff01;人工蜂群算法优化&#xff01;ABC-CNN-LSTM-MATT多特征分类预测 目录 一区大黄蜂&#xff01;人工蜂群算法优化&#xff01;ABC-CNN-LSTM-MATT多特征分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现ABC-CNN-LSTM-MATT人工蜂群…

PDF转JPG神器!一键转换,轻松搞定文档分享

各位亲爱的小伙伴们&#xff0c;有没有遇到过需要把PDF文件转换成JPG图片的情况呢&#xff1f;今天我就来给大家推荐几款好用的PDF转JPG工具&#xff0c;让我们一起来看看这些工具的详细介绍和使用感受吧&#xff01; 一、福昕转换器 直通车&#xff08;粘贴到浏览器打开&…

获取时隔半个钟的三天与el-time-select

摘要&#xff1a; 今天遇到需求是配送时间&#xff0c;时隔半个钟的排线&#xff01;所以需要拼接时间&#xff01;例如2024-10-08 14&#xff1a;30&#xff0c;2024-10-08 15&#xff1a;00&#xff0c;2024-10-08 15&#xff1a;30 <el-form-item label"配送时间&a…

优先算法1--双指针

“一念既出&#xff0c;万山无阻。”加油陌生人&#xff01; 目录 1.双指针--移动零 2.双指针-复写零 ok&#xff0c;首先在学习之前&#xff0c;为了方便大家后面的学习&#xff0c;我们这里需要补充一个知识点&#xff0c;我这里所谓的指针&#xff0c;不是之前学习的带有…

如何构建高效的公路工程资料管理系统?

本文介绍了构建高效的公路工程资料管理系统的方法&#xff0c;涵盖了系统需求分析、功能设计、开发平台选择、开发过程、系统上线与培训、持续改进与维护等关键环节。通过合理规划和科学管理&#xff0c;可以确保系统满足用户需求&#xff0c;提高工作效率&#xff0c;保障公路…

react18+react-transition-group实现路由切换过度

效果如下 官网安装对应的插件 创建对应的样式 .fade-enter {opacity: 0; } .fade-exit {opacity: 1; } .fade-enter-active {opacity: 1; } .fade-exit-active {opacity: 0; } .fade-enter-active, .fade-exit-active {transition: opacity 500ms; }const location useLoca…

STM32 | STM32F4OTA_ESP8266_Bootloader为引导程序远程更新的代码(APP)

更新。点击上方"蓝字"关注我们 01、思路 >>> STM32F4OTA_ESP8266_Bootloader为引导程序 远程更新的代码&#xff08;APP&#xff09;:远程更新的APP Ymoden_server&#xff1a;为运行在Linux的TCP服务器 备注&#xff1a;STM32 OTA远程更新需要连接热点 电…

【实战项目】——Boost搜索引擎(五万字)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、项目的相关背景 1.1、什么是Boost库&#xff1f; 1.2、什么是搜索引擎&#xff1f; 1.3、为什么要做Boost库搜索引擎&#xff1f; 二、搜索引擎的宏观原…