unity-调用讯飞星火语音唤醒-新版windowsSDK

news2024/10/7 12:22:16

调用讯飞星火语音唤醒-新版windowsSDK

先贴一张在unity中 wins系统下成功调用新版的讯飞windowsSDK的运行截图

调用成功为什么要用讯飞的语音唤醒?
项目中需要在unity和win系统下进行语音唤醒开启语音对话,而语音唤醒比较成熟的方案大多都是在linux系统下的,如snowboy,还有就是安卓系统的语音唤醒(各大厂都有)。win系统的就很少,我了解到的也只有讯飞有在做win系统的语音唤醒,如果从linux和安卓将语音唤醒功能移植到win下,不知道要花费多少时间。因此选择了讯飞

为什么要用这个新版的windowsSDK?

  1. 新版便宜。在官方费用上可以看到,旧版的低消为8000(最近618活动打折到了5600);而新版的低消为2500,打折后为1750
  2. 唤醒词设置方便。旧版需要在讯飞的官网上设置唤醒词,然后下载整个sdk,然后将sdk中的wakeupresource.jet文件替换,才能完成唤醒词的修改,并且如果你的语音唤醒过期了她还会提示你无法下载…;新版的sdk经过测试,将唤醒词以txt文本的方式写在了本地,也就意味着你直接在本地修改txt文件就可以完成唤醒词的修改,极大的减轻了开发人员的额外工作
  3. 与时俱进,新版肯定较旧版而言更有优势才会出新版

然而旧版的语音唤醒也还是有它的优势的

  1. 网上已经有很多调用旧版sdk的教程,跟着写就可以实现windowsSDK语音唤醒(是的我就是其中之一),无需将时间耗费在亲自写代码去调用dll中提供的api等各种繁琐而且有难度的事情上。官方的windowsSDK是dll的形式,如果不懂c++以及C#调用dll的代码的话,自己写会十分痛苦和消耗时间;新版的由于推出较晚,使用的人不多,网上相关的教程更是基本没有,问客服也是一问三不知,我手撸了差不多一个星期才实现了基本的调用。
  2. 旧版的语音唤醒和语音识别是连在一起的,唤醒搞定之后识别和合成等的的调用流程都是一样的,不需要太多额外的工作
  3. 新版的sdk中在c++环境下调用是否快速,但在dll调用中则困难重重

大家可以权衡利弊,选择合适自己项目的语音唤醒(讯飞原版及新版)

在讯飞官网中下载新版的源码后,可以在visual studio中试运行,看看体验如何,官方的demo中是提供了读取本地音频进行唤醒识别和实时通过麦克风接收到的数据进行唤醒识别两个选项

时间关系,先直接贴上调用成功的代码

public class MSCDLL : MonoBehaviour
{
    private const string _ability = "e867a88f2"; //这是默认的,请不要修改
    private const string _appID = "在官网上申请的应用的appid";
    private const string _apiSecret = "秘钥";
    private const string _apiKey = "key";
    private const string TAG = "MSCDLL";
    int _dll_result = 0;
    IntPtr _akikt_handle = IntPtr.Zero;
    // Start is called before the first frame update
    void Start()
    {
        byte[] bytes = ReadWavFile($"{Application.streamingAssetsPath}/output.wav");
        wakeup(bytes);//测试直接读取本地的音频,将其直接传给唤醒的api进行唤醒识别   
    }

    public void wakeup(byte[] bytes)
    {//卸载&释放语音唤醒sdk资源
        _dll_result = AIKIT_UnInit();
        Debug.Log($"{TAG}>>>AIKIT_UnInit>>>{(_dll_result == 0 ? "success" : "fail")}");

        //初始化并设置语音唤醒参数
        AIKIT_InitParam param = new AIKIT_InitParam();
        param.AppID = _appID;
        param.ApiSecret = _apiSecret;
        param.ApiKey = _apiKey;
        param.AuthType = 0;
        _dll_result = AIKIT_Init(param);
        Debug.Log($"{TAG}>>>AIKIT_InitParam>>>{(_dll_result == 0 ? "success" : "fail")}");

        //注册回调
        AIKIT_OnOutput onOutput = new AIKIT_OnOutput(OnOutput);
        AIKIT_OnEventDelegate onEvent = new AIKIT_OnEventDelegate(OnEvent);
        AIKIT_OnErrorDelegate onError = new AIKIT_OnErrorDelegate(OnError);
        AIKIT_Callbacks callbacks = new AIKIT_Callbacks
        {
            outputCB = onOutput,
            eventCB = onEvent,
            errorCB = onError
        };
        _dll_result = AIKIT_RegisterAbilityCallback(_ability, callbacks);
        Debug.Log($"{TAG}>>>AIKIT_RegisterAbilityCallback>>>{(_dll_result == 0 ? "success" : "fail")}");

        //初始化语音唤醒引擎
        AIKIT_BaseParam engintParam = null;
        int resutl2 = AIKIT_EngineInit(_ability, engintParam);
        Debug.Log($"{TAG}>>>AIKIT_EngineInit>>>{(_dll_result == 0 ? "success" : "fail")}");

        //加载唤醒所需要的资源参数>>>唤醒词文件路径
        string value = (Application.streamingAssetsPath + "\\xbxb.txt").Replace("/", "\\").Replace("\\", "\\\\");
        IntPtr tem = Marshal.StringToHGlobalAnsi(value);
        AIKIT_CustomData loadData = new AIKIT_CustomData("key_word", tem, 2);
        _dll_result = AIKIT_LoadData(_ability, loadData);
        Debug.Log($"{TAG}>>>AIKIT_LoadData>>>{(_dll_result == 0 ? "success" : "fail")}");

        //指定要使用的唤醒词文件数据集合,每次会话开启前需要调用。
        _dll_result = AIKIT_SpecifyDataSet(_ability, "key_word", new int[] { 0 }, 1);
        Debug.Log($"{TAG}>>>AIKIT_SpecifyDataSet>>>{(_dll_result == 0 ? "success" : "fail")}");
        //设置唤醒词文件的参数
        IntPtr aikit_handle_ptr = AIKITBuilder_Create(BuilderType.BUILDER_TYPE_PARAM);
        AIKITBuilderHandle aikit_param_handle = (AIKITBuilderHandle)Marshal.PtrToStructure(aikit_handle_ptr, typeof(AIKITBuilderHandle));
        _dll_result = AIKITBuilder_AddBool(aikit_param_handle, "gramLoad", true);//这一个字段不添加会报错无法运行
        //result = AIKITBuilder_AddString(aikit_handle, "wdec_param_nCmThreshold", "0 0:999", "0 0:999".Length);//这个可以不添加
        IntPtr param_ptr = AIKITBuilder_BuildParam(aikit_param_handle);
        AIKIT_BaseParam aikit_param = (AIKIT_BaseParam)Marshal.PtrToStructure(param_ptr, typeof(AIKIT_BaseParam));
        Debug.Log($"{TAG}>>>AIKITBuilder_BuildParam>>>{(_dll_result == 0 ? "success" : "fail")}");

        //开启唤醒>>>同时返回句柄,用于给>>>AIKIT_WRITE>>>当做参数调用,这个句柄包含了会话信息,如果不一致无法执行后面的write和end这两个函数
        _dll_result = AIKIT_Start(_ability, aikit_param, IntPtr.Zero, ref _akikt_handle);
        Debug.Log($"{TAG}>>>AIKIT_Start>>>{(_dll_result == 0 ? "success" : "fail")}>>>{_dll_result}");

        IntPtr aikit_data_handle_ptr = AIKITBuilder_Create(BuilderType.BUILDER_TYPE_DATA);
        AIKITBuilderHandle aikit_data_handle = (AIKITBuilderHandle)Marshal.PtrToStructure(aikit_data_handle_ptr, typeof(AIKITBuilderHandle));
        //将音频数据引到指定对象中,并传给dll
        BuilderData builderData = new BuilderData();
        builderData.type = (int)BuilderDataType.DATA_TYPE_AUDIO;
        builderData.name = "wav";
        builderData.status = 0;
        builderData.data = bytes;
        builderData.len = bytes.Length;
        _dll_result = AIKITBuilder_AddBuf(aikit_data_handle, builderData);
        Debug.Log($"{TAG}>>>AIKITBuilder_AddBuf>>>{(_dll_result == 0 ? "success" : "fail")}>>>{_dll_result}");

        //将数据对象传给dll后,调用dll的api获取根据数据对象生成的inputdata对象
        IntPtr data_ptr = AIKITBuilder_BuildData(aikit_data_handle);
        //将获取到的dataptr指针强转成我们需要的对象
        AIKIT_BaseData input_data = (AIKIT_BaseData)Marshal.PtrToStructure(data_ptr, typeof(AIKIT_BaseData));

        //将获取到的inputdata对象传入>>>AIKIT_Write>>>开始检测唤醒
        AIKIT_HANDLE aikit_handle = (AIKIT_HANDLE)Marshal.PtrToStructure(_akikt_handle, typeof(AIKIT_HANDLE));
        _dll_result = AIKIT_Write(aikit_handle, input_data);

        Debug.Log($"{TAG}>>>AIKIT_Write>>>{(_dll_result == 0 ? "success" : "fail")}>>>{_dll_result}");

        _dll_result = AIKIT_End(aikit_handle);
        Debug.Log($"{TAG}>>>AIKIT_End>>>{(_dll_result == 0 ? "success" : "fail")}>>>{_dll_result}");


    }
    // Update is called once per frame
    void Update()
    {

    }
    /// <summary>
    /// 卸载释放sdk
    /// </summary>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_UnInit();

    /// <summary>
    /// 初始化sdk
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_Init(AIKIT_InitParam data);
    /// <summary>
    /// 初始化引擎
    /// </summary>
    /// <param name="appid"></param>
    /// <param name="param"></param>
    /// <returns></returns>
    [DllImport("AEE_lib")]
    public static extern Int32 AIKIT_EngineInit(string appid, AIKIT_BaseParam param);
    /// <summary>
    /// 卸载释放引擎
    /// </summary>
    /// <param name="appid"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_EngineUnInit(string appid);
    /// <summary>
    /// 注册回调
    /// </summary>
    /// <param name="appid"></param>
    /// <param name="param"></param>
    /// <returns></returns>

    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_RegisterAbilityCallback(string appid, AIKIT_Callbacks param);

    /// <summary>
    /// 设置唤醒的参数
    /// </summary>
    /// <param name="appid"></param>
    /// <param name="param"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_LoadData(string appid, AIKIT_CustomData param);
    /// <summary>
    /// 设置唤醒词文件信息
    /// </summary>
    /// <param name="appid"></param>
    /// <param name="key"></param>
    /// <param name="index"></param>
    /// <param name="count"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_SpecifyDataSet(string appid, string key, int[] index, int count);

    /// <summary>
    /// 添加AIKITBuilderHandle对象
    /// </summary>
    /// <param name="builderType"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr AIKITBuilder_Create(BuilderType builderType);
    /// <summary>
    /// 通过AIKITBuilderHandle对象设置bool类型的参数
    /// </summary>
    /// <param name="handle"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKITBuilder_AddBool(AIKITBuilderHandle handle, string key, bool value);
    /// <summary>
    /// 通过AIKITBuilderHandle对象设置string类型的参数
    /// </summary>
    /// <param name="handle"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="len"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKITBuilder_AddString(AIKITBuilderHandle handle, string key, string value, int len);
    /// <summary>
    /// 通过AIKITBuilderHandle对象输入BuilderData对象,对象中记录字节数据
    /// </summary>
    /// <param name="handle"></param>
    /// <param name="builderData"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKITBuilder_AddBuf(AIKITBuilderHandle handle, BuilderData builderData);
    /// <summary>
    /// 通过AIKITBuilderHandle对象将刚才设置好的参数转成AIKIT_BaseParam对象
    /// </summary>
    /// <param name="handle"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr AIKITBuilder_BuildParam(AIKITBuilderHandle handle);
    /// <summary>
    /// 通过AIKITBuilderHandle对象将刚才设置好的参数转成>>>AIKITBuilder_BuildData>>>对象
    /// </summary>
    /// <param name="handle"></param>
    /// <returns></returns>
    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr AIKITBuilder_BuildData(AIKITBuilderHandle handle);
    /// <summary>
    /// 正式开启唤醒
    /// </summary>
    /// <param name="appid"></param>
    /// <param name="param"></param>
    /// <param name="userContext"></param>
    /// <param name="outHandle"></param>
    /// <returns></returns>

    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_Start(string appid, AIKIT_BaseParam param, IntPtr userContext, ref IntPtr outHandle);
    /// <summary>
    /// 传入需要唤醒检测的数据文件
    /// </summary>
    /// <param name="appid"></param>
    /// <param name="param"></param>
    /// <param name="userContext"></param>
    /// <param name="outHandle"></param>
    /// <returns></returns>

    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_Write(AIKIT_HANDLE handle, AIKIT_BaseData input);

    [DllImport("AEE_lib", CallingConvention = CallingConvention.StdCall)]
    public static extern Int32 AIKIT_End(AIKIT_HANDLE handle);

    public static byte[] ReadWavFile(string filePath)
    {
        // 确保文件存在
        if (!File.Exists(filePath))
        {
            Debug.Log(filePath);
            throw new FileNotFoundException("文件未找到", filePath);
        }

        // 读取文件的所有字节
        byte[] fileBytes = File.ReadAllBytes(filePath);
        return fileBytes;
    }

    private void OnOutput(IntPtr handle, AIKIT_BaseDataList output)
    {   // 处理输出回调
        //将Intprt转成aikitoutputdata,然后获取输出结果

        AIKIT_HANDLE output_handle = (AIKIT_HANDLE)Marshal.PtrToStructure(handle, typeof(AIKIT_HANDLE));
        Debug.Log(output_handle.abilityID);
        //AIKIT_BaseDataList input_data = (AIKIT_BaseDataList)Marshal.PtrToStructure(output, typeof(AIKIT_BaseDataList));
        Debug.Log("唤醒成功!");
    }
    private void OnEvent(IntPtr handle, int eventType, IntPtr eventValue)
    {   // 处理事件回调// 处理输出回调
        Debug.Log(eventValue);
    }
    private void OnError(IntPtr handle, int err, IntPtr desc)
    {   // 处理错误回调
        Debug.Log(desc);
    }
}
[StructLayout(LayoutKind.Sequential)]

public class AIKIT_InitParam
{
    public int AuthType;         // 授权方式,0=设备级授权,1=应用级授权  
    public string AppID;         // 应用id  
    public string ApiKey;        // 应用key  
    public string ApiSecret;     // 应用secret  
    public string WorkDir;       // sdk工作目录,需可读可写权限  
    public string ResDir;        // 只读资源存放目录,需可读权限  
    public string LicenseFile;   // 离线激活方式的授权文件存放路径,为空时需联网进行首次在线激活  
    public string BatchID;       // 授权批次  
    public string UDID;          // 用户自定义设备标识  
    public string CfgFile;       // 配置文件路径,包括文件名  
}
[StructLayout(LayoutKind.Sequential)]

public class AIKIT_BaseParam
{
    public IntPtr next; // 链表指针,使用IntPtr代替void*指针
    public IntPtr key; // 指针,使用IntPtr代替const char*
    public IntPtr value; // 指针,使用IntPtr代替void*
    public IntPtr reserved; // 预留字段,使用IntPtr代替void*
    public int len; // 数据长度
    public int type; // 变量类型
}
[StructLayout(LayoutKind.Sequential)]

public class AIKIT_CustomData
{
    public IntPtr Next;
    public byte[] KeyBytes;
    public IntPtr Value;
    public IntPtr Reserved;
    public int Index;
    public int Len;
    public int From;


    public AIKIT_CustomData(string key, IntPtr value, int from, int index = 0, int len = 0)
    {
        KeyBytes = Encoding.UTF8.GetBytes(key + "\0");
        Value = value;
        From = from;
        Index = index;
        Len = len;
        Reserved = IntPtr.Zero;
        Next = IntPtr.Zero;
    }

}
[StructLayout(LayoutKind.Sequential)]
public class AIKIT_HANDLE
{
    public IntPtr usrContext;
    public string abilityID;
    public IntPtr handleID;
}
[StructLayout(LayoutKind.Sequential)]
public class AIKITBuilderHandle
{
    public IntPtr builderInst;
    public BuilderType type;
}

public enum BuilderType
{
    BUILDER_TYPE_PARAM,
    BUILDER_TYPE_DATA
}
public enum BuilderDataType
{
    DATA_TYPE_TEXT,           // 文本
    DATA_TYPE_AUDIO,          // 音频
    DATA_TYPE_IMAGE,          // 图片
    DATA_TYPE_VIDEO           // 视频
}
[StructLayout(LayoutKind.Sequential)]
public class AIKIT_BaseData
{
    public IntPtr next; // 链表指针,使用IntPtr代替void*指针
    public AIKIT_BaseParam desc; // 指针,使用IntPtr代替const char*
    public string key;
    public IntPtr value; // 指针,使用IntPtr代替void*
    public IntPtr reserved; // 预留字段,使用IntPtr代替void*
    public int len; // 数据长度
    public int type; // 变量类型
    public int status; // 变量类型
    public int from; // 变量类型
}

[StructLayout(LayoutKind.Sequential)]
public class BuilderData
{
    public int type;    // 数据类型
    public string name; // 数据段名
    public byte[] data; // 数据段实体(当送入路径时,此处传入路径地址字符串指针即可;
    public int len;     // 数据段长度(当送入路径或文件句柄时,此处传0即可)
    public int status;  // 数据段状态,参考AIKIT_DataStatus枚举
}
// 定义委托类型
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void AIKIT_OnOutput(IntPtr handle, AIKIT_BaseDataList output);
public delegate void AIKIT_OnEventDelegate(IntPtr handle, int eventType, IntPtr eventValue);
public delegate void AIKIT_OnErrorDelegate(IntPtr handle, int err, IntPtr desc);

// 定义与C++结构体对应的C#结构体

// 定义与C++结构体对应的C#结构体
[StructLayout(LayoutKind.Sequential)]
public struct AIKIT_Callbacks
{
    public AIKIT_OnOutput outputCB;
    public AIKIT_OnEventDelegate eventCB;
    public AIKIT_OnErrorDelegate errorCB;
}



[StructLayout(LayoutKind.Sequential)]
public class AIKIT_BaseDataList
{
    public IntPtr node;
    //public AIKIT_BaseData node;
    public int count;
    public int totalLen;
}
  • 条件
    • 三个库文件
    • 一个唤醒词文件

先将官方的sdk中的三个库文件导入到unity中(项目assets文件夹中创建一个bin文件夹/放在plugins中),两个dll,一个lib
然后在项目中的某个路径下添加唤醒词文件(txt)
记得唤醒词文件的路径,在代码中需要获取那个文件
然后就可以直接运行测试了
我本地跑了很多次都是成功的,有问题可以留言

待解决的问题

  • 唤醒成功后的回调对象的转换还有问题
  • 哪些部分是初始化后不需要每次都调用的要和每次都需要调用的函数进行隔离
  • 代码整理,我将所有的逻辑都放在了一个类中,很不雅观

这次的代码之旅让我对指针和c++有了深刻的理解,在这几天的不断尝试中,我几度想放弃,网上关于sdk调用的知识很少,客服也是一问三不知,答非所问。不过还是坚持了下来…我可真是太棒了。
下班了就先写到这里了,有时间再把具体的实现流程补充一下吧
不过如果完整的看一遍下来,应该没什么问题,主要就是时间花在了读官方提供的demo源码以及自己根据源码中提供的api去模拟demo中的一些功能。
大概的情况就是,官方的demo源码中使用了很多工厂模式去新建对象,而在提供的dll中是没有这方面的函数的,刚官方的文档也是一点没写怎么不用工厂模式去新建对象。因此需要自己根据其他的函数,去模拟创建出工厂模式创建对象的过程。
当然看网上也有很多关于自己打dll包,将工厂模式之类没开放出来的函数开放出来,然后去调用那个自己打的dll包的说法,不过感觉目前我的能力还没有到那个水平就没有去尝试,有时间的话看看能不能摸索一下吧~

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

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

相关文章

CocosCreator 微信小游戏上架流程准备工作

前言 事前准备非常重要&#xff0c;因为有creator的助力&#xff0c;实际上开发小游戏往往很快&#xff0c;但是如果准备不足&#xff0c;上架及审核过程非常慢&#xff0c;往往游戏做好了&#xff0c;还得各种排队等审核&#xff0c;大多数开发者又不是腾讯白名单之内&#x…

甘肃的千层烤馍:传统面点的魅力绽放

千层烤馍&#xff0c;作为甘肃美食文化的重要象征&#xff0c;以其独特的外形和丰富的口感&#xff0c;吸引着众多食客。它的外观犹如一件精美的艺术品&#xff0c;层层叠叠&#xff0c;金黄酥脆&#xff0c;散发着诱人的香气。 在甘肃平凉地区制作千层烤馍&#xff0c…

windows10 编译libevent2.1.12

windows10 编译libevent2.1.12 nmake 编译libevent使用vs命令行工具2.编译命令3.编译出现问题 cmake 编译libevent nmake 编译libevent 使用vs命令行工具 2.编译命令 nmake /f Makefile.nmake3.编译出现问题 cmake 编译libevent cmake -S . -B build32 -A Win32 cd build32…

NXP i.MX8系列平台开发讲解 - 3.15 Linux 之USB子系统(一)

专栏文章目录传送门&#xff1a;返回专栏目录 Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 目录 Linux 之USB子系统(一) 1. USB基础简介 1.1 USB的传输模式 1.2 USB 的设备描述符 1.3 USB 类的定义分类 2…

IK分词器热刷新词库实践分享

目录 前言 什么是分词器&#xff1f; ik分词器简介 ik分词器和默认分词器的对比 ik分词器介绍 ik分词器的分词问题 自定义词库 主配置解说 通过配置文件自定义词库 Step1: 新建自定义分词库 Step2: 将我们的自定义词添加到ik的配置文件中 Step3: 重启es&#xff0c;…

DSP C6000教学实验箱操作教程_数字图像处理:5-3 图像缩放

一、实验目的 学习图像缩放的原理&#xff0c;掌握图像的读取方法&#xff0c;并实现图像缩放。 二、实验原理 图像缩放 在计算机图像处理和计算机图形学中&#xff0c;图像缩放是指对数字图像的大小进行调整的过程。图像缩放是一种非平滑的过程&#xff0c;需要在处理效率以…

通过“BOSS”精通比特币,深入认识私钥、账户和钱包

来源:币界原创 作者:636Marx 无论当今数字货币技术如何发展&#xff0c;认识区块链技术幕后的关键机制至关重要。无论您是新手还是经验丰富的数字货币从业者&#xff0c;掌握钱包地址、公钥和私钥的复杂性都有无可替代重要性。进入 BOSS Wallet&#xff0c;这是一款尖端的 Web…

Kubernates容器化JVM调优笔记(内存篇)

Kubernates容器化JVM调优笔记&#xff08;内存篇&#xff09; 先说结论背景思路方案 先说结论 1、首先如果是JDK8&#xff0c;需要使用JDK8_191版本以上&#xff0c;才支持容器化环境和以下参数&#xff0c;否则就更新到JDK10以上&#xff0c;选择对应的镜像构建就行了 2、在容…

day01-anaconda的安装

Anaconda的安装 参考地址&#xff1a; http://t.csdnimg.cn/mUmSp 安装完毕&#xff0c;可以卸载电脑中的其他python版本&#xff0c;在控制面板中进行卸载。 在命令行指令中输入 pythonPython 3.8.3 (default, Jul 2 2020, 17:30:36) [MSC v.1916 64 bit (AMD64)] :: An…

【React 】折叠面板,点击展开时再请求数据

需求背景&#xff1a;使用折叠面板的形式展示数据&#xff0c;面板内部数据需要在打开时请求接口获取。 遇到问题&#xff1a;最开始使用Antd 的折叠面板组件&#xff0c;它对于数据直接渲染是没问题的&#xff0c;但是不好满足打开面板时再动态加载数据的需求&#xff0c;于是…

兴业严选|朝阳、大兴、丰台、等5.9折起总有一套适合你~

近日于上海&#xff0c;出现了一桩令人始料未及之事。一套地处浦东、面积达 245.7 平方米的住宅进行挂网拍卖。 出乎意料的是&#xff0c;此套房子受到众多买家的青睐&#xff0c;历经一番激烈的竞价竞争&#xff0c;最终以 1766 万元的价格成交&#xff0c;折合每平方米 7187…

kakfa发版丢消息事件分析

背景 其他部门同事反馈在项目发版/重启(kill -15)的那段时间&#xff0c;经常会出现导致 C 端业务出现问题&#xff0c;从而产生资损 一听资损&#xff0c;赶紧应答下来&#xff0c;了解了下具体情况&#xff0c;然后立马去排查了 问题分析 结合同事的描述以及对业务的了解&a…

8小时出500杯,投诉三次辞退?Manner逼疯员工…?

一边歇斯底里的咆哮&#xff1a;「你投诉啊」&#xff01;一边将咖啡粉泼向顾客……一场大战要不是隔着岛台&#xff0c;就真的燃起来了……‍ 好巧不巧&#xff0c;同一天&#xff0c;另一段视频中的顾客就没那么好运了&#xff0c;男店员冲上去就给女顾客一个耳光……‍‍ 想…

【ai】tx2-nx 开通samba

ubutn服务器加入了samba给jetson也加入一个samba 添加root用户 密码与nvidia一样 添加nvidia 到suoders中并添加samba账号 nvidia@tx2-nx:~$ nvidia@tx2-nx:~$ nvidia@tx2-nx:~$ nvidia@tx2-nx:~$ sudo vi /etc/sudoers nvidia@tx2-nx:~$ sudo chm

成熟的自动化运维平台有哪些特点?

点击进入运维资料库 在现代企业运维中&#xff0c;自动化运维平台已经成为不可或缺的工具。随着技术的发展&#xff0c;企业对系统稳定性和效率的要求越来越高&#xff0c;传统的手工运维方式已无法满足需求。于是&#xff0c;自动化运维平台应运而生&#xff0c;成为提升运维效…

泵设备的监测控制和智慧运维

泵是一种输送流体或使流体增压的机械。它通过各种工作原理&#xff08;如离心、柱塞等&#xff09;将机械能转换为流体的动能或压力能&#xff0c;从而实现液体的输送、提升、循环等操作。 泵的一些具体应用场景&#xff1a; 1.智能水务&#xff1a;在城市供水管网中&#xff…

推动产业数字化转型,六个方面引领变革

从工业经济时代走向数字经济时代&#xff0c;世界经济发生着全方位、革命性的变化&#xff0c;产业数字化便是最显著的表现之一。当前&#xff0c;产业数字化不断深入发展&#xff0c;平台经济、工业互联网、智能制造等新业态、新模式不断涌现&#xff0c;成为了数字经济的重要…

【element-ui】el-date-picker动态设置picker-options

<el-date-pickerv-model"formObj.startDate"type"date"placeholder"开始时间":picker-options"startPickerOptions"> </el-date-picker><el-date-pickerv-model"formObj.endDate"type"date"placeh…

【linux】内核源码TCP->IP->L2层函数调用继续摸索中

日志打印的时候&#xff0c;把行数也打印了&#xff1a; 登录 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/commit/b847489a9910f68b9581fd8788807c697c82cdbd 上回基于应用层wget操作找到TCP调用的一些接口&#xff0c;并且已经到IP层的一些接口&#xff0c;当前基…

vue2与vue3数据响应式对比之检测变化

vue2 由于javascript限制&#xff0c;vue不能检测数组和对象的变化 什么意思呢&#xff0c;举例子来说吧 深入响应式原理 对象 比如说我们在data里面定义了一个info的对象 <template><div id"app"><div>姓名: {{ info.name }}</div><…