拍手切换暗/亮模式

2025-05-24

拍手切换暗/亮模式

这篇文章最初发表在我的博客上

几天前,我们在Netlify 应用上发布了暗黑模式测试版。虽然我们仍在不断改进,但目前只能通过Netlify 实验室以及用户设置来使用。

尽管到达那里不需要点击很多次,但对我来说感觉太多了,在等待在导航中轻松访问它时,我想知道......如果能够通过拍手来切换它,就像一些家庭自动化设备一样,那不是很有趣吗?

因此,我花了周末的一部分时间研究如何构建它,最终使用 TensorFlow.js 构建了一个 Chrome 扩展程序和一个用我拍手样本训练的模型,可以打开/关闭暗模式!

结果如下:

拍手切换暗模式,然后再次拍手切换亮模式

有趣!!!😃或者至少对我来说...

所以,下面就是我的做法。

训练模型

首先,我训练了模型,以确保能够识别拍手的声音。为了更轻松、更快速地完成训练,我使用了Teachable Machine平台,更具体地说,我启动了一个音频项目

第一部分是录制你当前的背景声音。然后,你可以创建多个“类”,用于录制你想在项目中使用的活动的声音样本,在本例中是拍手的声音。

一般来说,如果我知道我将在有更多种类声音的环境中使用这个模型,我会为更多的类别录制样本。

例如,我还录制了语音样本,以便模型能够识别语音的“样子”,而不会将其误认为是拍手。

完成样本记录后,您可以继续训练模型,预览其是否按预期工作并将其导出以在您的代码中使用它。

构建 Chrome 扩展程序

我不会详细介绍如何构建 Chrome 扩展程序,因为有很多不同的选项,但以下是我为自己所做的。

您至少需要一个manifest.json包含有关您的扩展的详细信息的文件。

{
  "name": "Dark mode clap extension",
  "description": "Toggle dark mode by clapping your hands!",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": ["storage", "activeTab"],
  "action": {
    "default_icon": {
      "16": "/images/dark_mode16.png",
      "32": "/images/dark_mode32.png",
      "48": "/images/dark_mode48.png",
      "128": "/images/dark_mode128.png"
    }
  },
  "icons": {
    "16": "/images/dark_mode16.png",
    "32": "/images/dark_mode32.png",
    "48": "/images/dark_mode48.png",
    "128": "/images/dark_mode128.png"
  },
  "content_scripts": [
    {
      "js": ["content.js"],
      "matches": ["https://app.netlify.com/*"],
      "all_frames": true
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

该项目最重要的部分是权限和内容脚本。

内容脚本

内容脚本是在网页上下文中运行的文件,因此它们可以访问浏览器当前正在访问的页面。

根据文件中的配置manifest.json,这将在任何选项卡或仅特定选项卡上触发。由于我添加了参数"matches": ["https://app.netlify.com/*"],,因此仅当我使用 Netlify 应用时才会触发。

然后,我可以开始触发专用于声音检测的代码。

设置 TensorFlow.js 来检测声音

使用 TensorFlow.js 时,我通常会将模型导出为文件保存在自己的机器上,但这次我决定使用另一种方式,将其上传到 Google Cloud。这样,就可以通过 URL 访问它了。

对于代码示例,当您导出模型时,Teachable 机器上会提供一个示例,但基本上,您需要从创建模型开始:

const URL = SPEECH_MODEL_TFHUB_URL; //URL of your model uploaded on Google Cloud.
const recognizer = await createModel();

async function createModel() {
  const checkpointURL = URL + "model.json";
  const metadataURL = URL + "metadata.json"; // model metadata

  const recognizer = speechCommands.create(
    "BROWSER_FFT",
    undefined,
    checkpointURL,
    metadataURL
  );

  await recognizer.ensureModelLoaded();
  return recognizer;
}
Enter fullscreen mode Exit fullscreen mode

完成后,您可以开始实时预测:

const classLabels = recognizer.wordLabels(); // An array containing the classes trained. In my case ['Background noise', 'Clap', 'Speech']

recognizer.listen(
  (result) => {
    const scores = result.scores; // will be an array of floating-point numbers between 0 and 1 representing the probability for each class
    const predictionIndex = scores.indexOf(Math.max(...scores)); // get the max value in the array because it represents the highest probability
    const prediction = classLabels[predictionIndex]; // Look for this value in the array of trained classes

    console.log(prediction);
  },
  {
    includeSpectrogram: false,
    probabilityThreshold: 0.75,
    invokeCallbackOnNoiseAndUnknown: true,
    overlapFactor: 0.5,
  }
);
Enter fullscreen mode Exit fullscreen mode

如果一切顺利,当此代码运行时,它应该根据实时音频数据的预测记录“背景噪音”,“拍手”或“语音”。

现在,为了切换 Netlify 的暗黑模式,我console.log用一些小逻辑替换了之前的语句。目前暗黑模式的实现方式是tw-dark在 body 上添加一个 class。

if (prediction === "Clap") {
  if (document.body.classList.contains("tw-dark")) {
    document.body.classList.remove("tw-dark");
    localStorage.setItem("nf-theme", "light");
  } else {
    document.body.classList.add("tw-dark");
    localStorage.setItem("nf-theme", "dark");
  }
}
Enter fullscreen mode Exit fullscreen mode

我还更新了 localStorage 中的值,以便将其保留下来。

安装扩展

为了能够测试此代码是否有效,您必须在浏览器中安装扩展程序。

(在此之前,您可能必须捆绑您的扩展,具体取决于您使用的工具。)

要安装它,请遵循以下步骤:

  • 访问chrome://extensions
  • Developer mode位于页面右上角的切换按钮
  • 单击Load unpacked并选择包含捆绑扩展的文件夹

如果一切顺利,您应该访问您想要运行扩展程序的任何页面,它应该请求麦克风权限才能检测实时音频,并开始预测!

--

就是这样!总的来说,这个项目其实跟切换暗黑模式没什么关系,但我一直想学习如何在 Chrome 扩展程序中使用 TensorFlow.js,所以这看起来是个绝佳的机会!😃

如果您想查看代码,这里是 repo

现在,我可以把它从我永无止境的清单上划掉了。✅

文章来源:https://dev.to/devdevcharlie/toggle-dark-light-mode-by-clapping-your-hands-li7
PREV
5 个实用的 JavaScript 初学者技巧。技巧 1:从数组中删除重复项!技巧 2:将十进制数转换为整数。技巧 3:获取数组的最后一个值!技巧 4:从数组中获取随机索引值。技巧 5:检测数组中最长的单词 :)
NEXT
在 Node.js 模块中运行勒索软件攻击