在 X 上發文後反應比預期中熱烈,因此公開了原始碼,想玩的朋友可以在自己的環境中進行編譯,享受一下〜
今年是我參加討厭應用程式 Advent Calendar 的第 8 年,我是黑神(@kokushing)。
突然想問,你知道 Discord 的音效板功能嗎?
在通話中按下 🎉 按鈕時會出現的這個。

這是通話中可以在任意時刻按下按鈕,向通話參加者播放已註冊音源的功能。
我覺得這是一個神奇的功能,可以用流行的迷因音源來活躍氣氛,或者在某人失誤時進行補救。不需要設定系統聲音,因此任何人都能輕易使用,真是太棒了。
不過,這樣的音效板功能也有幾個不便之處。
第一點是無可奈何,但第二點個人覺得有點可惜。我認為每個人有不同的情況,但我總是容易錯過播放時機…。
至於快捷鍵設定的部分,雖然只要設定就好,但這功能為了奪走珍貴的快捷鍵空間,我覺得也沒那麼重要…這樣的感覺。
這些問題的解決方案,就是我今天要介紹的這個討厭應用。
它的名字是 「Super Soundboard」。
這裡是實際運作的視頻(雖然沒有聲音,但實際上有在講話)
這不是 Discord 的應用擴展,而是以 Discord Bot 的形式重現音效板功能。
使用這個應用,你可以:
這樣一來,即使專注於遊戲,也能用聲音作為觸發,來活躍氣氛!
這次實作中最大的瓶頸就是 語音轉文字 的詞彙偵測部分。
我個人的座右銘是讓這個討厭應用的開銷降到最低,所以不可以使用有償 API,這樣做是違反規則的。到了第 8 年,這種限制玩法也變得有趣起來。
因此我打算用本地 LLM 來實作,但手邊只有 M1 Pro 環境,嘗試過 faster-whisper,但效果不佳,無法得到滿意的精度和速度,讓我感到悲傷。
所以我決定使用 Google Chrome 內建的 Web Speech API 來實作。
使用這個 API,只需幾行程式碼便可輕鬆實現語音轉文字。
// 初始化
const rec = new SpeechRecognition();
rec.lang = "ja-JP";
rec.continuous = true; // 連續識別
rec.interimResults = true; // 也接收中間結果
// 結果事件(分開處理確定和中間結果)
rec.onresult = (e: SpeechRecognitionEvent) => {
let interim = "";
let appendedFinal = "";
for (let i = e.resultIndex; i < e.results.length; i++) {
const text = e.results[i][0].transcript;
if (e.results[i].isFinal) appendedFinal += text;
else interim += text;
}
// appendedFinal 是「確定字串」,interim 是「途中文字串」
// setFinalText(prev => prev + appendedFinal)
// setInterimText(interim)
};
// 開始 / 停止
rec.start();
rec.stop();
文字轉錄的精度和速度都相當不錯,當我找到這個 API 時,能免費使用這個品質讓我感到驚訝。
恰好在討厭應用程式 Advent Calendar 主辦者的あんど(@ampersand_xyz)的貼文正在熱傳,而 Prompt API 的多模態性能也不錯。
使用這個 API 的討厭應用程式似乎也很有趣。
此外,Discord Bot 是用官方的 discord.js 快速實作。
通過 WebSocket 與客戶端連接,將偵測到的音源數據發送到 Bot 並播放。
音源是從這個網站借來的。
我實際上用這個應用與朋友一起玩 Apex Legends,因為能夠在恰當的時機加入音效,所以我們度過了充滿歡笑的時間。
我個人最喜歡的流程是「武器大丈夫嗎?」→「沒問題,完全沒問題」→「用 PayPay 買」→「paypay♪」。
能夠隨興而作地快速開發出這樣的應用,真的是一個好時代…。
我已經期待明年的討厭應用程式 Advent Calendar 了!