Unity3D开发AI桌面精灵/宠物系列 【三】 语音识别 ASR 技术、语音转文本多平台 - 支持科大讯飞、百度等 C# 开发

news2025/4/16 9:55:54

Unity3D 交互式AI桌面宠物开发系列【三】ASR 语音识别


该系列主要介绍怎么制作AI桌面宠物的流程,我会从项目开始创建初期到最终可以和AI宠物进行交互为止,项目已经开发完成,我会仔细梳理一下流程,分步讲解。 这篇文章主要讲有关于语音识别 ASR 方面的一些方法。


提示:内容纯个人编写,欢迎评论点赞,来指正我。

文章目录

  • Unity3D 交互式AI桌面宠物开发系列【三】ASR 语音识别
  • 前言
  • 一、语音识别 (ASR) 概述
  • 二、Unity开发准备阶段
    • 1.Unity平台
    • 2.示例:讯飞平台
  • 三、科大讯飞 ASR 短语音识别API
    • 1. 创建应用
    • 2. 查看免费测试服务量
    • 3. 查看 WebSocket 接口信息
    • 4. API 开发文档查看
  • 四、功能开发阶段
    • 1. Unity界面开发
    • 2. 代码分析
    • 3. 代码片段
    • 4. 数据配置
    • 5. 效果展示
    • 6. 问题反馈
    • 然后就,大功告成了!!!
  • 总结


前言

本篇内容主要讲Unity开发桌面宠物的语音识别功能,大家感兴趣也可以了解一下这个开发方向,目前还是挺有前景的,AI智能科技发展这么迅猛,紧跟步伐哈~

下面让我们出发吧 ------------>----------------->


一、语音识别 (ASR) 概述

语音识别(Automatic Speech Recognition,ASR)是一种技术,指的是通过计算机程序和算法,将人类所说的语音信号转化为文字或其他形式的电子文本的过程。ASR系统通过分析语音信号中包含的声音波形、频谱和语音特征等信息,识别并转录出语音中所包含的文字内容。这项技术在语音识别软件、智能语音助手、语音搜索、电话客服系统等领域有着广泛的应用。

在这里插入图片描述

二、Unity开发准备阶段

1.Unity平台

  • 该系列全部使用Unity2021.3.44开发;
  • 该系列前后文章存在关联,不懂的可以看前面文章;
  • 该系列完成之后我会上传源码工程,着急的小伙伴可以自己写框架,我就先编写各模块的独立功能。

2.示例:讯飞平台

  • 注册讯飞账户,已注册的直接登录;
  • 创建语音识别应用,然后 领取 语音识别 (短语音识别) 免费测试服务量绑定该应用,或者付费购买服务量;(个人认证可以领取免费服务量)
  • 前两步我就不贴流程图了,该系列在上节的语音唤醒文章中提到过注册和领取相关功能免费服务量的流程;

  • 上述操作很简单
  • 重点来了,科大讯飞平台的ASR接口怎么接入,下面来看一下吧

三、科大讯飞 ASR 短语音识别API

1. 创建应用

在这里插入图片描述在这里插入图片描述

  • 点击用户下面的 “我的应用” 然后创建应用,命名语音识别的应用,创建成功后会生成一个APPKey或者APPID 保存好。(名字随便起,记住APPID,后续要用到)

2. 查看免费测试服务量

在这里插入图片描述

  • 个人测试的话领取免费开发测试服务量就可以了,商用的话就购买相应的服务量。

3. 查看 WebSocket 接口信息

在这里插入图片描述

  • 记录保存该各项数据,后续在WebSocket连接的时候要用到这些。

4. API 开发文档查看

在这里插入图片描述

  • 这里有开发文档可以自行查看并学习,当然我是看过的,那么接下来就到了开发阶段了!
  • ps: 记住这个接口地址,这是WebSocket的API 地址 (调用的网址),接下来会用到。

四、功能开发阶段

1. Unity界面开发

在这里插入图片描述

  • ① 用于显示识别内容的 Text 文本
  • ② 用于按住进行录音操作的 Button 按钮
  • ③ 用于显示按钮的提示词的 Text 文本
  • ④ 用于挂载ASR语音识别 脚本 的空物体

2. 代码分析

在这里插入图片描述

  • 参数:用于定义变量;
  • 语音输入:用于录制音频片段;
  • 获取鉴权Url:用于鉴权加密的API地址;
  • 语音识别:用于实现语音识别的API接口调用功能;
  • 工具方法:用于处理Unity中的音频片段,转换成讯飞标准格式;
  • 数据定义:用于定义发送数据和接收数据的数据结构,根据第三方平台的参数数据。

3. 代码片段

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class XunfeiSpeechToText : MonoBehaviour
{
    #region 参数
    /// <summary>
    /// host地址
    /// </summary>
    [SerializeField] private string m_HostUrl = "iat-api.xfyun.cn";
    /// <summary>
    /// 语言
    /// </summary>
    [SerializeField] private string m_Language = "zh_cn";
    /// <summary>
    /// 应用领域
    /// </summary>
    [SerializeField] private string m_Domain = "iat";
    /// <summary>
    /// 方言mandarin:中文普通话、其他语种
    /// </summary>
    [SerializeField] private string m_Accent = "mandarin";
    /// <summary>
    /// 音频的采样率
    /// </summary>
    [SerializeField] private string m_Format = "audio/L16;rate=16000";
    /// <summary>
    /// 音频数据格式
    /// </summary>
    [SerializeField] private string m_Encoding = "raw";

    /// <summary>
    /// websocket
    /// </summary>
    private ClientWebSocket m_WebSocket;
    /// <summary>
    /// 传输中断标记点
    /// </summary>
    private CancellationToken m_CancellationToken;
    /// <summary>
    /// 语音识别API地址
    /// </summary>
    [SerializeField]
    [Header("语音识别API地址")]
    private string m_SpeechRecognizeURL;
    /// <summary>
    /// 讯飞的AppID
    /// </summary>
    [Header("填写APP ID")]
    [SerializeField] private string m_AppID = "讯飞的AppID";
    /// <summary>
    /// 讯飞的APIKey
    /// </summary>
    [Header("填写Api Key")]
    [SerializeField] private string m_APIKey = "讯飞的APIKey";
    /// <summary>
    /// 讯飞的APISecret
    /// </summary>
    [Header("填写Secret Key")]
    [SerializeField] private string m_APISecret = "讯飞的APISecret";
    /// <summary>
    /// 计算方法调用的时间
    /// </summary>
    [SerializeField] protected System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
    #endregion
    private void Awake()
    {
        //注册按钮事件
        RegistButtonEvent();
        //绑定地址 地址就是讯飞平台上的 WebSocket API地址
        m_SpeechRecognizeURL = "wss://iat-api.xfyun.cn/v2/iat";
    }

    #region 语音输入
    /// <summary>
    /// 语音输入的按钮
    /// </summary>
    [SerializeField] private Button m_VoiceInputBotton;
    /// <summary>
    /// 录音按钮的文本
    /// </summary>
    [SerializeField] private Text m_VoiceBottonText;
    /// <summary>
    /// 录音的提示信息
    /// </summary>
    [SerializeField] private Text m_RecordTips;

    /// <summary>
    /// 录制的音频长度
    /// </summary>
    public int m_RecordingLength = 5;

    /// <summary>
    /// 临时接收音频的片段
    /// </summary>
    private AudioClip recording;

    /// <summary>
    /// 注册按钮事件
    /// </summary>
    private void RegistButtonEvent()
    {
        if (m_VoiceInputBotton == null || m_VoiceInputBotton.GetComponent<EventTrigger>())
            return;
        EventTrigger _trigger = m_VoiceInputBotton.gameObject.AddComponent<EventTrigger>();
        //添加按钮按下的事件
        EventTrigger.Entry _pointDown_entry = new EventTrigger.Entry();
        _pointDown_entry.eventID = EventTriggerType.PointerDown;
        _pointDown_entry.callback = new EventTrigger.TriggerEvent();
        //添加按钮松开事件
        EventTrigger.Entry _pointUp_entry = new EventTrigger.Entry();
        _pointUp_entry.eventID = EventTriggerType.PointerUp;
        _pointUp_entry.callback = new EventTrigger.TriggerEvent();
        //添加委托事件
        _pointDown_entry.callback.AddListener(delegate { StartRecord(); });
        _pointUp_entry.callback.AddListener(delegate { StopRecord(); });
        _trigger.triggers.Add(_pointDown_entry);
        _trigger.triggers.Add(_pointUp_entry);
    }

    /// <summary>
    /// 开始录制
    /// </summary>
    public void StartRecord()
    {
        m_VoiceBottonText.text = "正在录音中...";
        StartRecordAudio();
    }
    /// <summary>
    /// 结束录制
    /// </summary>
    public void StopRecord()
    {
        m_VoiceBottonText.text = "按住按钮,开始录音";
        m_RecordTips.text = "录音结束,正在识别...";
        StopRecordAudio(AcceptClip);
    }

    /// <summary>
    /// 开始录制声音
    /// </summary>
    public void StartRecordAudio()
    {
        recording = Microphone.Start(null, true, m_RecordingLength, 16000);
    }

    /// <summary>
    /// 结束录制,返回audioClip
    /// </summary>
    /// <param name="_callback"></param>
    public void StopRecordAudio(Action<AudioClip> _callback)
    {
        Microphone.End(null);
        _callback(recording);
    }

    /// <summary>
    /// 处理录制的音频数据
    /// </summary>
    /// <param name="_data"></param>
    public void AcceptClip(AudioClip _audioClip)
    {

        m_RecordTips.text = "正在进行语音识别...";
        SpeechToText(_audioClip, DealingTextCallback);
    }

    /// <summary>
    /// 处理识别到的文本
    /// </summary>
    /// <param name="_msg"></param>
    private void DealingTextCallback(string _msg)
    {
        //在此处处理接收到的数据,可以选择发送给大模型,或者打印测试,会在后续补充功能
        m_RecordTips.text = _msg;
        Debug.Log(_msg);
    }


    #endregion

    #region 获取鉴权Url

    /// <summary>
    /// 获取鉴权url
    /// </summary>
    /// <returns></returns>
    private string GetUrl()
    {
        //获取时间戳
        string date = DateTime.Now.ToString("r");
        //拼接原始的signature
        string signature_origin = string.Format("host: " + m_HostUrl + "\ndate: " + date + "\nGET /v2/iat HTTP/1.1");
        //hmac-sha256算法-签名,并转换为base64编码
        string signature = Convert.ToBase64String(new HMACSHA256(Encoding.UTF8.GetBytes(m_APISecret)).ComputeHash(Encoding.UTF8.GetBytes(signature_origin)));
        //拼接原始的authorization
        string authorization_origin = string.Format("api_key=\"{0}\",algorithm=\"hmac-sha256\",headers=\"host date request-line\",signature=\"{1}\"", m_APIKey, signature);
        //转换为base64编码
        string authorization = Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization_origin));
        //拼接鉴权的url
        string url = string.Format("{0}?authorization={1}&date={2}&host={3}", m_SpeechRecognizeURL, authorization, date, m_HostUrl);

        return url;
    }

    #endregion

    #region 语音识别

    /// <summary>
    /// 语音识别
    /// </summary>
    /// <param name="_clip"></param>
    /// <param name="_callback"></param>
    public void SpeechToText(AudioClip _clip, Action<string> _callback)
    {
        byte[] _audioData = ConvertClipToBytes(_clip);
        StartCoroutine(SendAudioData(_audioData, _callback));
    }
    /// <summary>
    /// 识别短文本
    /// </summary>
    /// <param name="_audioData"></param>
    /// <param name="_callback"></param>
    /// <returns></returns>
    public IEnumerator SendAudioData(byte[] _audioData, Action<string> _callback)
    {
        yield return null;
        ConnetHostAndRecognize(_audioData, _callback);
    }

    /// <summary>
    /// 连接服务,开始识别
    /// </summary>
    /// <param name="_audioData"></param>
    /// <param name="_callback"></param>
    private async void ConnetHostAndRecognize(byte[] _audioData, Action<string> _callback)
    {
        try
        {
            stopwatch.Restart();
            //建立socket连接
            m_WebSocket = new ClientWebSocket();
            m_CancellationToken = new CancellationToken();
            Uri uri = new Uri(GetUrl());
            await m_WebSocket.ConnectAsync(uri, m_CancellationToken);
            //开始识别
            SendVoiceData(_audioData, m_WebSocket);
            StringBuilder stringBuilder = new StringBuilder();
            while (m_WebSocket.State == WebSocketState.Open)
            {
                var result = new byte[4096];
                await m_WebSocket.ReceiveAsync(new ArraySegment<byte>(result), m_CancellationToken);
                //去除空字节
                List<byte> list = new List<byte>(result); while (list[list.Count - 1] == 0x00) list.RemoveAt(list.Count - 1);
                string str = Encoding.UTF8.GetString(list.ToArray());
                //获取返回的json
                ResponseData _responseData = JsonUtility.FromJson<ResponseData>(str);
                if (_responseData.code == 0)
                {
                    stringBuilder.Append(GetWords(_responseData));
                }
                else
                {
                    PrintErrorLog(_responseData.code);

                }
                m_WebSocket.Abort();
            }

            string _resultMsg = stringBuilder.ToString();

            //识别成功,回调
            _callback(_resultMsg);

            stopwatch.Stop();
            if (_resultMsg.Equals(null) || _resultMsg.Equals(""))
            {
                Debug.Log("语音识别为空字符串");
            }
            else
            {
                //识别的数据不为空 在此处做功能处理

            }
            Debug.Log("讯飞语音识别耗时:" + stopwatch.Elapsed.TotalSeconds);
        }
        catch (Exception ex)
        {
            Debug.LogError("报错信息: " + ex.Message);
            m_WebSocket.Dispose();
        }
    }

    /// <summary>
    /// 获取识别到的文本
    /// </summary>
    /// <param name="_responseData"></param>
    /// <returns></returns>
    private string GetWords(ResponseData _responseData)
    {
        StringBuilder stringBuilder = new StringBuilder();
        foreach (var item in _responseData.data.result.ws)
        {
            foreach (var _cw in item.cw)
            {
                stringBuilder.Append(_cw.w);
            }
        }

        return stringBuilder.ToString();
    }


    private void SendVoiceData(byte[] audio, ClientWebSocket socket)
    {
        if (socket.State != WebSocketState.Open)
        {
            return;
        }
        PostData _postData = new PostData()
        {
            common = new CommonTag(m_AppID),
            business = new BusinessTag(m_Language, m_Domain, m_Accent),
            data = new DataTag(2, m_Format, m_Encoding, Convert.ToBase64String(audio))
        };

        string _jsonData = JsonUtility.ToJson(_postData);

        //发送数据
        socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(_jsonData)), WebSocketMessageType.Binary, true, new CancellationToken());
    }

    #endregion

    #region 工具方法
    /// <summary>
    /// audioclip转为byte[]
    /// </summary>
    /// <param name="audioClip"></param>
    /// <returns></returns>
    public byte[] ConvertClipToBytes(AudioClip audioClip)
    {
        float[] samples = new float[audioClip.samples];

        audioClip.GetData(samples, 0);

        short[] intData = new short[samples.Length];

        byte[] bytesData = new byte[samples.Length * 2];

        int rescaleFactor = 32767;

        for (int i = 0; i < samples.Length; i++)
        {
            intData[i] = (short)(samples[i] * rescaleFactor);
            byte[] byteArr = new byte[2];
            byteArr = BitConverter.GetBytes(intData[i]);
            byteArr.CopyTo(bytesData, i * 2);
        }

        return bytesData;
    }

    /// <summary>
    /// 打印错误日志
    /// </summary>
    /// <param name="status"></param>
    private void PrintErrorLog(int status)
    {
        if (status == 10005)
        {
            Debug.LogError("appid授权失败");
            return;
        }
        if (status == 10006)
        {
            Debug.LogError("请求缺失必要参数");
            return;
        }
        if (status == 10007)
        {
            Debug.LogError("请求的参数值无效");
            return;
        }
        if (status == 10010)
        {
            Debug.LogError("引擎授权不足");
            return;
        }
        if (status == 10019)
        {
            Debug.LogError("session超时");
            return;
        }
        if (status == 10043)
        {
            Debug.LogError("音频解码失败");
            return;
        }
        if (status == 10101)
        {
            Debug.LogError("引擎会话已结束");
            return;
        }
        if (status == 10313)
        {
            Debug.LogError("appid不能为空");
            return;
        }
        if (status == 10317)
        {
            Debug.LogError("版本非法");
            return;
        }
        if (status == 11200)
        {
            Debug.LogError("没有权限");
            return;
        }
        if (status == 11201)
        {
            Debug.LogError("日流控超限");
            return;
        }
        if (status == 10160)
        {
            Debug.LogError("请求数据格式非法");
            return;
        }
        if (status == 10161)
        {
            Debug.LogError("base64解码失败");
            return;
        }
        if (status == 10163)
        {
            Debug.LogError("缺少必传参数,或者参数不合法,具体原因见详细的描述");
            return;
        }
        if (status == 10200)
        {
            Debug.LogError("读取数据超时");
            return;
        }
        if (status == 10222)
        {
            Debug.LogError("网络异常");
            return;
        }
    }


    #endregion

    #region 数据定义

    /// <summary>
    /// 发送的数据
    /// </summary>
    [Serializable]
    public class PostData
    {
        [SerializeField] public CommonTag common;
        [SerializeField] public BusinessTag business;
        [SerializeField] public DataTag data;
    }

    [Serializable]
    public class CommonTag
    {
        [SerializeField] public string app_id = string.Empty;
        public CommonTag(string app_id)
        {
            this.app_id = app_id;
        }
    }
    [Serializable]
    public class BusinessTag
    {
        [SerializeField] public string language = "zh_cn";
        [SerializeField] public string domain = "iat";
        [SerializeField] public string accent = "mandarin";
        public BusinessTag(string language, string domain, string accent)
        {
            this.language = language;
            this.domain = domain;
            this.accent = accent;
        }
    }

    [Serializable]
    public class DataTag
    {
        [SerializeField] public int status = 2;
        [SerializeField] public string format = "audio/L16;rate=16000";
        [SerializeField] public string encoding = "raw";
        [SerializeField] public string audio = string.Empty;
        public DataTag(int status, string format, string encoding, string audio)
        {
            this.status = status;
            this.format = format;
            this.encoding = encoding;
            this.audio = audio;
        }
    }


    [Serializable]
    public class ResponseData
    {
        [SerializeField] public int code = 0;
        [SerializeField] public string message = string.Empty;
        [SerializeField] public string sid = string.Empty;
        [SerializeField] public ResponcsedataTag data;
    }

    [Serializable]
    public class ResponcsedataTag
    {
        [SerializeField] public Results result;
        [SerializeField] public int status = 2;
    }

    [Serializable]
    public class Results
    {
        [SerializeField] public List<WsTag> ws;
    }

    [Serializable]
    public class WsTag
    {
        [SerializeField] public List<CwTag> cw;
    }

    [Serializable]
    public class CwTag
    {
        [SerializeField] public int sc = 0;
        [SerializeField] public string w = string.Empty;
    }

    #endregion

}

4. 数据配置

在这里插入图片描述

  • 将APPid、ApiKey、SecretKey替换成自己讯飞平台上的 WebSocket 信息数据
  • 变量对应UI进行配置

5. 效果展示

在这里插入图片描述

  • 按住按钮进行录音,松开后进行识别,返回的结果会显示在UI界面上,就代表成功了。

在这里插入图片描述

  • 控制台会有打印结果的,也一样代表 API 接入成功。
  • 注意使用时,打开电脑麦克风权限

6. 问题反馈

  • 运行后有任何问题都可以在评论区进行讨论~
  • 代码写的不是很工整,多多指点,后续会进行整个系列的框架搭建
  • 下一期更新暂定:
    ① 其他平台ASR接入功能,例如:百度等
    ② 大模型LLM的接入,例如:讯飞、百度、GPT等
    二选一哦!
  • 评论告诉我,下一期更新什么

然后就,大功告成了!!!

在这里插入图片描述
比心啦 ❥(^_-)

在这里插入图片描述

总结

  • 提示: 大家根据需求来做功能,后续继续其他功能啦,不懂的快喊我。
  • 大家可以在评论区讨论其他系列下一期出什么内容,这个系列会继续更新的
  • 点赞收藏加关注哦~ 蟹蟹

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

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

相关文章

Qt -信号与槽

博客主页&#xff1a;【夜泉_ly】 本文专栏&#xff1a;【暂无】 欢迎点赞&#x1f44d;收藏⭐关注❤️ 目录 前言引入connect调用链模板类型的connectQObject::connectImplQObjectPrivate::connectImpl qobject_p_p.hconnect作用总结ai对信号与槽的模拟实现 前言 面向对象&am…

Django中使用不同种类缓存的完整案例

Django中使用不同种类缓存的完整案例 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 Django中使用不同种类缓存的完整案例步骤1:设置Django项目步骤2:设置URL路由步骤3:视图级别…

解锁健康密码,拥抱品质生活

在生活节奏不断加快的今天&#xff0c;健康养生已成为人们关注的焦点。它不仅关乎当下生活质量&#xff0c;更是对未来幸福的投资。从日常生活的点滴出发&#xff0c;掌握正确养生方法&#xff0c;我们就能轻松收获健康。​ 饮食是健康的基石。我们应当遵循 “食物多样&#x…

ABAP 新语法 - corresponding

在 ABAP 中&#xff0c;CORRESPONDING 操作符用于根据字段名称自动映射结构体&#xff08;Structure&#xff09;或内表&#xff08;Internal Table&#xff09;的字段值。它比传统的 MOVE-CORRESPONDING 语句更灵活&#xff0c;支持更多控制选项。 基础用法 data: begin of …

HTML零基础入门笔记:狂神版

前言 本笔记是学习狂神的java教程&#xff0c;建议配合视频&#xff0c;学习体验更佳。 【狂神说Java】HTML5完整教学通俗易懂_哔哩哔哩_bilibili 第1-2章&#xff1a;Java零基础入门笔记&#xff1a;(1-2)入门&#xff08;简介、基础知识&#xff09;-CSDN博客 第3章&…

FreeRTOS移植笔记:让操作系统在你的硬件上跑起来

一、为什么需要移植&#xff1f; FreeRTOS就像一套"操作系统积木"&#xff0c;但不同硬件平台&#xff08;如STM32、ESP32、AVR等&#xff09;的CPU架构和外设差异大&#xff0c;需要针对目标硬件做适配配置。移植工作就是让FreeRTOS能正确管理你的硬件资源。 二、…

c语言修炼秘籍 - - 禁(进)忌(阶)秘(技)术(巧)【第五式】动态内存管理

c语言修炼秘籍 - - 禁(进)忌(阶)秘(技)术(巧)【第五式】动态内存管理 【心法】 【第零章】c语言概述 【第一章】分支与循环语句 【第二章】函数 【第三章】数组 【第四章】操作符 【第五章】指针 【第六章】结构体 【第七章】const与c语言中一些错误代码 【禁忌秘术】 【第一式…

MySQL表的增删改查基础版

这一部分内容比较多&#xff0c;请大家结合目录查看&#x1f440; 增删改查 这一部分内容比较多&#xff0c;请大家结合目录查看&#x1f440; 一、新增1.插入2.指定列插入3.一次插入多行记录 二、查询1.全列查询2.指定列查询3.查询字段为表达式4.别名5.去重6.多列去重7.排序8.…

【备赛】蓝桥杯嵌入式实现led闪烁

原理 由于蓝桥杯的板子带有锁存器&#xff0c;并且与lcd屏幕有冲突&#xff0c;所以这个就成了考点。 主要就是用定时器来实现&#xff0c;同时也要兼顾lcd的冲突。 一、处理LCD函数 首先来解决与lcd屏幕冲突的问题&#xff0c;把我们所有用到的lcd函数改装一下。 以下是基…

【Python】贝叶斯,条件概率是怎么回事儿

【Python】贝叶斯&#xff0c;条件概率是怎么回事儿 一、原理简介1.1 贝叶斯定理1.2 朴素贝叶斯假设 二、算法实现过程2.1 数据准备与预处理2.2 模型训练与预测2.2.1 高斯朴素贝叶斯 - 对应连续型数据2.2.2 多项式朴素贝叶斯 - 离散型数据 2.3 模型评估 三、算法优缺点分析3.1 …

Flink介绍——实时计算核心论文之Storm论文详解

引入 我们通过以下两篇文章&#xff0c;深入探索了S4是如何抽象流式计算模型&#xff0c;如何设计架构和系统&#xff0c;存在那些局限&#xff1a; 论文详解论文总结 Yahoo推出的S4 并没有在历史舞台上站稳脚跟&#xff0c;在S4的论文发表的同一年&#xff0c;我们今天的主…

001 使用单片机实现的逻辑分析仪——吸收篇

本内容记录于韦东山老师的毕设级开源学习项目&#xff0c;含个人观点&#xff0c;请理性阅读。 个人笔记&#xff0c;没有套路&#xff0c;一步到位&#xff0c;欢迎交流&#xff01; 00单片机的逻辑分析仪与商业版FPGA的逻辑分析仪异同 对比维度自制STM32逻辑分析仪商业版逻…

11-产品经理-创建产品

在“产品”-“仪表盘”内&#xff0c;可以查看系统中关于产品及相关需求的统计。 在“产品”-“产品列表”页面&#xff0c;可以按项目集、项目查看其关联产品。还可以添加产品、编辑产品线、或者导出产品列表。 产品看板&#xff0c;通过看板方式查看产品、产品计划和产品下的…

低代码开发平台:飞帆制作网页并集成到自己的网页中

应用场景&#xff1a; 有时&#xff0c;我们的网页使用了某个模版&#xff0c;或者自己写的 html、css、javascript 代码。只是网页中的一部分使用飞帆来制作。这样的混合网页如何实现呢&#xff1f; 其实很容易&#xff0c;来体验一下飞帆提供的功能&#xff01; 还记得这个…

语法: result=log (x);

LOG( ) 语法: resultlog (x); 参数: x是一个浮点数; 返回值: result等于返回值,是一个浮点数; 功能: 该函数是用来计算浮点数x的自然对数(即ln x);如果x小于或等于0,或x太大,则行为没有定义; 注意:存在error挂起; 如果在编写程序里包含了errno.h头文件,则范围和等级…

Hibernate核心方法总结

Session中的核心方法梳理 1、save方法 这个方法表示将一个对象保存到数据库中&#xff0c;可以将一个不含OID的new出来的临时对象转换为一个处于Session缓存中具有OID的持久化对象。 需要注意的是&#xff1a;在save方法前设置OID是无效的但是也不会报错&#xff0c;在save方…

IntelliJ IDEA Maven 工具栏消失怎么办?

一、问题现象与背景 在使用 IntelliJ IDEA&#xff08;简称 IDEA&#xff09;开发 Maven 项目时&#xff0c;偶尔会遇到右侧或侧边栏的 Maven 工具栏&#xff08;显示依赖、生命周期等信息的窗口&#xff09;突然消失的情况。这可能影响开发者快速操作 Maven 构建、依赖管理等…

消息队列(kafka 与 rocketMQ)

为什么要使用消息队列?作用1: 削峰填谷(突发大请求量问题)作用2: 解耦(单一原则)作用3: 异步(减少处理时间) 如何选择消息队列(kafka&RocketMQ)成本功能性能选择 rocketMQ是参考kafka进行实现的为什么rocketMQ与kafka性能差距很大呢?kafka 的底层数据储存实现rocketMQ 的…

【STM32】Flash详解

【STM32】Flash详解 文章目录 【STM32】Flash详解1.Flash闪存概念1. 1核心区别&#xff1a;NOR Flash vs. NAND Flash1.2 为什么常说的“Flash”多指 NAND Flash&#xff1f;1.3技术细节对比(1) 存储单元结构(2) 应用场景(3) 可靠性要求 1.4总结 2.STM32内部的Flash2.1为什么是…

CV - 目标检测

物体检测 目标检测和图片分类的区别&#xff1a; 图像分类&#xff08;Image Classification&#xff09; 目的&#xff1a;图像分类的目的是识别出图像中主要物体的类别。它试图回答“图像是什么&#xff1f;”的问题。 输出&#xff1a;通常输出是一个标签或一组概率值&am…