当前位置: 首页 > news >正文

【香橙派系列教程】(四)基于ARM-Linux架构的语音控制刷抖音项目

【四】基于ARM-Linux架构的语音控制刷抖音项目

文章目录

  • 【四】基于ARM-Linux架构的语音控制刷抖音项目
    • 1.语音模块配置
      • 1.创建产品
      • 2.引脚配置
      • 3.词条定义
      • 4.添加控制
      • 5.发布版本
      • 6.烧录固件
    • 2.编程实现语音和开发板通信
    • 3.手机接入Linux热拔插
      • 1.dmesg命令
      • 2.adb调试
        • 踩坑问题
      • 3.总结
    • 4. 用shell指令来操作手机屏幕,模拟手动滑屏幕
    • 5.整合
      • 接线图
      • 代码

1.语音模块配置

整体逻辑是:

  1. 语音模块负责接收用户说话的信息,通过串口发送给H616
  2. H616写好业务逻辑的处理,当接收不同信号时来处理不同的业务
  3. 通过USB接口连接手机,利用adb指令来控制安卓手机

安卓的底层是Linux,所以也可以接收一些Linux指令

智能公元:智能公元/AI产品零代码平台 (smartpi.cn)

进入官方平台,配置词条和识别后的串口输出指令。

1.创建产品

这里用到的语音模块型号为SU-03T

2.引脚配置

3.词条定义

4.添加控制

5.发布版本

其他的选项可以自行探索

6.烧录固件

首先连接好串口(记得交叉接线),插到电脑上面下载固件

下载需要冷启动:先把模块断电,然后点下载,下载进度变黄,之后再给模块上电

TXGPIO_B7
RXGPIO_B6

1.下载SDK固件包(里面自带烧录工具)

2.找到烧录工具

烧录器

固件位置与烧录器一个位置

开始烧录

烧录完固件之后,可以插到电脑上面配合串口助手看一下发送的信息

2.编程实现语音和开发板通信

首先将语音与开发板通过串口进行连接。

编译我们上一篇写的串口代码:

多文件编译方法: “ * ”为通配符,统一编译所有以uartT开头的文件

运行:

因为输出是乱码,所以需要我们修改一下发送的函数。

uartTool.c

//加入这段话
char myserialGetchar (const int fd)
{char x ;if (read (fd, &x, 1) != 1)return -1 ;return x ;
}

uartTool.h

char myserialGetchar (const int fd);

uartTest.c

添加串口读取一个字符的接口

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include "uartTool.h"
int fd;
void* readSerial()
{char cmd;while(1){cmd = myserialGetchar(fd);switch(cmd){case 'N':printf("next\n");break;case 'P':printf("pre\n");break;case 'Z':printf("zan\n");break;case 'Q':printf("qu\n");break;}}
}
int main(int argc, char **argv)
{char deviceName[32] = {'\0'};pthread_t readt;if(argc < 2){printf("uage:%s /dev/ttyS?\n",argv[0]);return -1;}strcpy(deviceName, argv[1]);if( (fd = myserialOpen(deviceName, 115200)) == -1){printf("open %s error\n",deviceName);return -1;}pthread_create(&readt, NULL, readSerial,NULL);while(1){sleep(10);}
}

3.手机接入Linux热拔插

1.dmesg命令

Linux dmesg(英文全称:display message):命令用于显示开机信息。

用法:dmesg

说明:查看所有开机日志信息

  • kernel 会将开机信息存储在 ring buffer 中。您若是开机时来不及查看信息,可利用 dmesg 来查看。
  • 开机信息亦保存在 /var/log 目录中,名称为 dmesg 的文件里。

1、查看命令版本

(base) [root@s186 ~]# dmesg -V
dmesg,来自 util-linux 2.23.2

2.过滤想查看信息

建议使用-i参数过滤时忽略大小写
(base) [root@s186 ~]# dmesg |grep -i cpu

2.adb调试

第一步:连接

用Type-c连接手机和orangepi zero2

输入指令查看usb设备:dmesg

此时能看到usb设备号和名称,这时只是单纯的识别了这个usb设备,但没有什么办法调试这个手机。

第二步:调试

如何调试?使用adb指令

//查看adb是否安装
adb version
//默认是没有安装adb的,安装指令:
sudo apt-get -y install adb//调试
adb devices
//进入shell指令
adb shell

踩坑问题

**第一个坑:**OK了,还有一个点我们需要注意的是要打开手机的开发者选项 -> USB调试功能,不然就会出现以下情况

即使我们已经连接成功了,dmesg也能监测到,但是还是看不到任何信息。

我们打开手机USB调试功能之后,再次运行:

手机会弹出来usb调试确认界面,需要手动点击确认(有时候弹不出来,拔插多试试)

到此adb 和Android连接成功,此时adb可以调试Android,通过shell指令控制手机。

**第二个坑:**当我输入adb shell时,也会报错

这是我出现的一种情况1:

手机:选择USB用于传输文件,可以进入adb调试,但是到达shell指令这块会出问题

这个的解决办法在第三个坑介绍

还有另外一种情况2:

手机:选择USB用于仅充电,直接卡在访问设备这里,进入不了adb调试

没有访问权限,也就是没有生成文件柄,应用层无法操作接入的硬件设备:

此时,需要配置文件,以支持USB设备的热拔插,支持UDEV的机制

linux下一切皆文件:
udev机制:说白了就是为插入或者拔掉的设备,添加文件柄删除文件柄。

  1. 在/etc/udev/rules.d文件夹下创建规则文件
cd /etc/udev/rules.d/
sudo vim oppo-android.rules
  1. 在文件中添加内容
//1.USB子系统       2.环境变量:USB设备                  3.权限
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0666"

**第三个坑:**当我使用adb指令的时候,始终报错这个

这是因为adb工具是安装在orangepi上面的,进入手机的shell指令肯定是找不到的,我们需要退回orangepi的命令行,就可以正常使用adb shell指令了。


3.总结

a. 把手机接入开发板
b. 安装adb工具,在终端输入adb安装指令: sudo apt-get install adb
c. dmeg能查看到手机接入的信息,但是输入adb devices会出现提醒dinsufficient permissions for device: user in plugdev group; are your udevrules wrong?
d. 配置文件,以支持USB设备的热拔插,支持UDEV的机制在/etc/udev/rules.d 文件夹下创建规则文件cd /etc/udev/rules.d/sudo vim 51-android.rules在文件中添加内容 SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0666"
e. 在手机开发者选项中,打开USB调试,重新拔插手机
f. 手机弹出调试提醒,点确认手机调试模式

4. 用shell指令来操作手机屏幕,模拟手动滑屏幕

目前我们语音控制刷抖音,只需要这四个指令即可。

adb shell input swipe 540 1300 540 500 100 //向下滑动 540是水平的,1300是竖直方向,下是500,100是100毫秒内完成
adb shell input swipe 540 500 540 1300 100 //向上滑动
adb shell "seq 2 | while read i;do input tap 350 1050 & input tap 350 1050 & sleep 0.2;done;" //点赞
adb shell input keyevent 26 //锁屏

这里多介绍一些常用的shell指令(吃不饱的同学可以加餐哈!哈哈哈哈)

1.adb相关命令

  1. 关闭adb服务:adb kill-server

  2. 开启adb服务:adb start-server

  3. 查看当前连接的手机设备:adb devices

  4. 多设设备操作,< -s 虚拟设备名称 >

  5. 重启设备:adb reboot 指定虚拟设备: adb -s 设备名称 reboot

  6. 查看日志: adb logcat 清除日志: adb logcat -c

  7. 进入linux shell下 adb shell 其中常用的linux命令 cd cat 等等 输入su可以获取超级管理员名称了 要确定是否有哪些命令 进入 system/bin目录 就知道了

  8. 代理链接:adb connect [ip:post]

  9. 获取MAC地址:adb shell cat /sys/class/net/wlan0/address

  10. 安装应用:adb install <name.apk>

  11. 卸载安装包:adb uninstall <name.apk>

  12. 保存缓存文件重新安装:adb install -r <name.apk>

  13. 断开连接:adb disconnect <设备名>

  14. 文件复制到移动设备 ,后面跟设备目录:adb push filename /sdcard/

  15. 模拟位置点击(x,y):adb shell input tap

  16. 模拟滑动( x,yx1,y1 ),还可传入滑动缓冲:adb shell input swipe

  17. 获取当前页面的UI层 次,保存为xml文件:uiautomator dump dump: creates an XML dump of current UI hierarchy

18.模式实现输入:adb shell input text <输入任意内容>

2.adb模拟按键对照表

keycode含义
3HOME 键
4返回键
5打开拨号应用
6挂断电话
24增加音量
25降低音量
26电源键
27拍照(需要在相机应用里)
64打开浏览器
82菜单键
85播放/暂停
86停止播放
87播放下一首
88播放上一首
122移动光标到行首或列表顶部
123移动光标到行末或列表底部
126恢复播放
127暂停播放
164静音
176打开系统设置
187切换应用
207打开联系人
208打开日历
209打开音乐
210打开计算器
220降低屏幕亮度
221提高屏幕亮度
223系统休眠
224点亮屏幕
231打开语音助手
276如果没有 wakelock 则让系统休眠

调用实例说明:

命令: adb shell input keyevent <keycode>
  1. 示例,点击电源键:adb shell input keyevent 26  #执行效果相当于按电源键。
  2. 示例,输入"你好啊中国":adb shell input text "你好啊中国"  #执行效果相当于用户输入"你好啊中国"。
  3. 示例,模拟点击任何位置:adb shell input tap x y (x和y表示点击的坐标)

5.整合

接线图

语音模块

TXGPIO_B7
RXGPIO_B6

B6->8 B7->10

手机USB接口插到开发板上面。

代码

对于代码中system函数的使用,在进程一篇中有过讲解:进程

uartTest.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include "uartTool.h"
int fd;
void* readSerial()
{char cmd;while(1){cmd = myserialGetchar(fd);switch(cmd){case 'N':printf("next\n");system("adb shell input swipe 540 1300 540 500 100");break;case 'P':printf("pre\n");system("adb shell input swipe 540 500 540 1300 100");break;case 'Z':printf("zan\n");system("adb shell \"seq 2 | while read i;do input tap 350 1050 &input tap 350 1050 & sleep 0.2;done;\"");break;case 'Q':printf("qu\n");system("adb shell input keyevent 26");break;}}
}
int main(int argc, char **argv)
{char deviceName[32] = {'\0'};pthread_t readt;if(argc < 2){printf("uage:%s /dev/ttyS?\n",argv[0]);return -1;}strcpy(deviceName, argv[1]);if( (fd = myserialOpen(deviceName, 115200)) == -1){printf("open %s error\n",deviceName);return -1;}pthread_create(&readt, NULL, readSerial,NULL);while(1){sleep(10);}
}

uartTool.c

//uartTool.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "wiringSerial.h"
int myserialOpen (const char *device, const int baud)
{struct termios options ;speed_t myBaud ;int status, fd ;switch (baud){case 9600: myBaud = B9600 ; break ;case 115200: myBaud = B115200 ; break ;}if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)return -1 ;fcntl (fd, F_SETFL, O_RDWR) ;// Get and modify current options:tcgetattr (fd, &options) ;cfmakeraw (&options) ;cfsetispeed (&options, myBaud) ;cfsetospeed (&options, myBaud) ;options.c_cflag |= (CLOCAL | CREAD) ;options.c_cflag &= ~PARENB ;options.c_cflag &= ~CSTOPB ;options.c_cflag &= ~CSIZE ;options.c_cflag |= CS8 ;options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;options.c_oflag &= ~OPOST ;options.c_cc [VMIN] = 0 ;options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds)tcsetattr (fd, TCSANOW, &options) ;ioctl (fd, TIOCMGET, &status);status |= TIOCM_DTR ;status |= TIOCM_RTS ;ioctl (fd, TIOCMSET, &status);usleep (10000) ; // 10mSreturn fd ;
}
void serialSendstring (const int fd, const char *s)
{int ret;ret = write (fd, s, strlen (s));if (ret < 0)printf("Serial Puts Error\n");
}
int serialGetstring (const int fd, char *buffer)
{int n_read;n_read = read(fd, buffer,32);return n_read;
}
//加入这段话
char myserialGetchar (const int fd)
{char x ;if (read (fd, &x, 1) != 1)return -1 ;return x ;
}

uartTool.h

//**uartTool.h**
int myserialOpen (const char *device, const int baud);
void serialSendstring (const int fd, const char *s);
int serialGetstring (const int fd, char *buffer);
char myserialGetchar (const int fd);

编译gcc uartTest.c uartTool.c -pthread

运行./a.out /dev/ttyS5

相关文章:

【香橙派系列教程】(四)基于ARM-Linux架构的语音控制刷抖音项目

【四】基于ARM-Linux架构的语音控制刷抖音项目 文章目录 【四】基于ARM-Linux架构的语音控制刷抖音项目1.语音模块配置1.创建产品2.引脚配置3.词条定义4.添加控制5.发布版本6.烧录固件 2.编程实现语音和开发板通信3.手机接入Linux热拔插1.dmesg命令2.adb调试踩坑问题 3.总结 4.…...

Java----反射

什么是反射&#xff1f; 反射就是允许对成员变量、成员方法和构造方法的信息进行编程访问。换句话来讲&#xff0c;就是通过反射&#xff0c;我们可以在不需要创建其对象的情况下就可以获取其定义的各种属性值以及方法。常见的应用就是IDEA中的提示功能&#xff0c;当我…...

相似度计算方法

一、相似度计算方法 相似度算法是计算两个或多个对象之间相似程度的方法&#xff0c;这些对象可以是文本、图像、音频等不同类型的数据。在计算机科学、信息检索、推荐系统、数据挖掘等领域中&#xff0c;相似度算法具有广泛的应用。 二、应用场景 搜索引擎&#xff1a;用于文…...

Vue 点击markdown页内链接,路由设置不跳转

在路由index.js里添加路由守卫&#xff1a; router.beforeEach((to,from,next)>{//如果是md页内链接“#xxx”&#xff0c;则不跳转const hash window.location.hash;if(hash.startsWith(#)) {next(false);}else{...其他控制代码next();} });当markdown用[标题链接](#标题名…...

IOday4

一、思维导图 二、练习 1、使用父子进程完成两个文件的拷贝&#xff0c;父进程拷贝前一半内容&#xff0c;子进程拷贝后一半内容&#xff0c;子进程结束后退出&#xff0c;父进程回收子进程的资源 #include<myhead.h> int main(int argc, const char *argv[]) {//判断终…...

智能座舱背后主流车机平台(SA8155/SA8295)的高通Hexagon DSP是什么?

智能座舱背后主流车机平台(SA8155/SA8295)的高通Hexagon DSP是什么&#xff1f; 一、高通Hexagon DSP的辉煌发展历程 高通&#xff0c;作为全球领先的无线通信技术创新者&#xff0c;其处理器技术一直走在行业前列。随着智能手机和物联网设备的普及&#xff0c;对处理器性能的…...

linux进程控制——进程等待——wait、waitpid

前言&#xff1a;本节内容仍然是进程的控制&#xff0c;上一节博主讲解的是进程控制里面的进程创建、进程退出、终止。本节内容将讲到进程的等待——等待是为了能够将子进程的资源回收&#xff0c;是父进程等待子进程。 我们前面的章节也提到过等待&#xff0c; 那里的等待是进…...

Shell脚本的进程管理

进程管理是系统管理的重要方面&#xff0c;通过对进程的监控、启动、停止和重启&#xff0c;可以保证系统的稳定运行。Shell脚本是一种强大的工具&#xff0c;可以对进程进行自动化管理&#xff0c;提高效率和准确性。 参考&#xff1a;shell脚本进程管理 - CSDN文库 shell脚本…...

JLink烧录失败

1. 现象&#xff1a; 这个位置是灰色的&#xff0c;没有SW Device信息。 MDK下面的打印&#xff1a; J-Flash的打印&#xff1a; windows上面的弹框的现象没有截屏。 2. 解决办法&#xff1a; 1.打开J-Link Commander,输入unlock kinetis&#xff0c;看现象不起作用,网…...

Monorepo简介

Monorepo 第一章&#xff1a;与Monorepo的邂逅第二章&#xff1a;Multirepo的困境第三章&#xff1a;Monorepo的魔力 - 不可思议的解决问题能力第四章&#xff1a;Monorepo的挑战与应对策略第五章&#xff1a;总结第六章&#xff1a;参考 第一章&#xff1a;与Monorepo的邂逅 …...

SpringBoot打包为jar包,打包前注意事项及打包教程

在打包 Spring Boot 项目为 JAR 包之前&#xff0c;有一些重要的注意事项和步骤&#xff0c;以确保打包过程顺利并生成一个可正常运行的 JAR 包&#xff1a; 1. 检查依赖和版本 确保所有依赖项和插件版本是最新且兼容的&#xff0c;特别是 Spring Boot 版本和其相关依赖的版本…...

B端系统UI个性化设计:感受定制之美

B端系统UI个性化设计&#xff1a;感受定制之美 引言 艾斯视觉作为ui设计和前端开发从业者&#xff0c;其观点始终认为&#xff1a;在当今竞争激烈的商业环境中&#xff0c;B端&#xff08;Business-to-Business&#xff09;系统的设计不再仅仅是功能性的堆砌&#xff0c;而是…...

前端常用 utils 工具封装

// 函数防抖 export function debounce(fn, interval) {let timerreturn function (this, ...args) {clearTimeout(timer)const context thislet params [...args]timer setTimeout(() > {fn.call(context, ...params)}, interval || 1000)} }// 函数节流 export functio…...

项目都做完了,领导要求国际化????--JAVA后端篇

springboot项目国际化相信各位小伙伴都会&#xff0c;很简单&#xff0c;但是怎么项目都做完了&#xff0c;领导却要求国际化文件就很头疼了 国际化的SpringBoot代码&#xff1a; 第一步&#xff1a;创建工具类 /*** 获取i18n资源文件** author bims*/ public class Message…...

国内备受好评PostgreSQL数据库性能如何?

为什么国内很多数据库采用PostgreSQL数据库作为基础&#xff0c;再次开发自己的产品呢?不仅仅是因为PostgreSQL数据库开源免费、PostgreSQL 数据库的性能也是相当出色的&#xff0c;具有以下几个方面的特点&#xff1a; 1. 处理大规模数据&#xff1a; - 能够有效地管理和处…...

彻底搞懂前端跨域解决方案

一、浏览器的同源策略 1、同源策略概述 同源策略是浏览器为确保资料安全&#xff0c;而遵循的一种策略&#xff0c;该策略对访问资源进行了一些限制。 2、什么是源&#xff08;origin&#xff09;&#xff1f; 3、示例 4、同源请求 5、非同源请求 二、跨域会受到哪些限制 1…...

Kafka基础概念

MQ消息中间件 1&#xff09;总览&#xff1a; 消息中间件 这里我们主要学习的是kafka的基础概念 具体参考黑马头条&#xff1a;https://www.bilibili.com/video/BV1Qs4y1v7x4/?spm_id_from333.337.search-card.all.click 2&#xff09;消息中间件对比 3&#xff09;Kafka介…...

【论文阅读笔记】DeepCAD: A Deep Generative Network for Computer-Aided Design Models

1 引言 现有3D生成模型&#xff1a; 3D点云&#xff1a;大量离散的3D点组成的数据表示形式&#xff1b; 多边形网格&#xff1a;一系列相连的多边形组成的3D模型&#xff1b; 水平集场&#xff1a;使用数值函数来表示物体的边界&#xff0c;并根据函数值的正负来确定物体内部…...

《如鸢》开通官号,女性向游戏爆款预定

今天&#xff0c;备受瞩目的沉浸式剧情卡牌手游《如鸢》正式开通了官方社媒账号并发布了玩家信。 《如鸢》由灵犀互娱倾力打造&#xff0c;游戏不仅拥有跌宕起伏的权谋剧情&#xff0c;更采用Live2D技术&#xff0c;为玩家带来沉浸式的游戏体验&#xff0c;吸引了众多玩家关注。…...

OpenAI再下一城:发布Voice Engine,可使用文本和参考语音合成说话者的新语音!

转自 机器学习算法工程师 OpenAI又发布了一个最新的工作&#xff1a;Voice Engine。Voice Engine可以使用文本输入和单个 15 秒音频样本生成听起来自然且与原始说话者非常相似的语音。而且&#xff0c;一个小型模型仅通过一个 15 秒的样本就能创造出富有情感且逼真的语音。Voi…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

mac:大模型系列测试

0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何&#xff0c;是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试&#xff0c;是可以跑通文章里面的代码。训练速度也是很快的。 注意…...