当语音识别成了打工人的「摸鱼外挂」:Edge 浏览器专属 Hook 开发指南(Chrome 用户慎入)

一、摸鱼前的灵魂拷问:为什么必须用 Edge?

「小王,这个需求今晚...」(老板话音未落)
你默默打开 Edge,按下麦克风:「需求已记录,今晚加班(内心:加个屁班)」

Edge 专属特权
✅ 本地语音引擎(断网也能识别「老板傻逼」)
✅ 错误提示说人话(「麦克风没开?摸鱼也要专业~」)
✅ 防老板突袭设计(点击外部自动隐藏)

(Chrome 用户:NetworkError 会把你的摸鱼语录直接弹窗)

二、Hook 逐行解析:给语音识别穿「打工人保护甲」

1. 初始化:先查户口(非 Edge 用户劝退)

tsx

const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SpeechRecognition) {
  onError('请换Edge,Chrome连语音都要翻围墙!'); 
  return { isListening: false };
}

  • 代码翻译:检查浏览器血统,非 Edge / 老 Edge 直接踢馆
  • 摸鱼逻辑:Chrome 用户会收到「翻围墙」警告,防止他们用坏了怪你
  • 真实场景:同事用 Chrome 报错,你:「早说了 Edge 是摸鱼专用!」

2. 状态管理:摸鱼 / 搬砖一目了然(带重试次数)

tsx

const [isListening, setIsListening] = useState(false); // 摸鱼状态灯
const [retryCount, setRetryCount] = useState(0); // 摸鱼失败重试次数
const maxRetries = 3; // 最多允许3次摸鱼失败(超过就摆烂)

  • 状态机设计
    false → 搬砖模式(老板看你在敲键盘)
    true → 摸鱼模式(实际在语音输入「中午吃黄焖鸡」)
  • 重试机制:连续 3 次失败自动触发「摸鱼冷静期」

3. 识别器配置:摸鱼方言全支持

tsx

const recognition = new SpeechRecognition();
recognition.lang = 'zh-CN'; // 支持四川话「摸鱼」、东北话「唠嗑」
recognition.interimResults = false; // 不实时显示,防老板偷看屏幕
recognition.continuous = false; // 说一句停一句,省电保命

  • 方言彩蛋:设为zh-CN-Sichuan可识别川普「老子要摸鱼」
  • 防窥设计:只有说完才显示文字,老板扭头只看到空白

4. 启动函数:摸鱼前的最后检查

tsx

const startSpeechRecognition = () => {
  if (!navigator.onLine) { // 断网时自动切换本地模式
    onError('断网了?正好摸鱼~(Edge本地识别可用)');
    return;
  }
  try {
    recognition.start();
    setIsListening(true); // 摸鱼状态灯亮起(红色预警)
  } catch (e) {
    onError('启动失败?检查下麦克风,摸鱼也要专业!');
  }
};

  • 断网福利:Edge 本地引擎离线可用(Chrome 直接罢工)
  • 老板视角:看到你突然坐直,以为在认真开会(实际在语音骂他)

5. 停止函数:老板来了秒切状态

tsx

const stopSpeechRecognition = () => {
  recognition.stop();
  setIsListening(false); // 摸鱼灯熄灭(假装正经)
  setRetryCount(0); // 重置失败次数,准备下次摸鱼
};

  • 物理外挂:建议绑定耳机线插拔事件,老板靠近自动停止
  • 实战案例:老板拍肩瞬间,语音输入「这需求非常合理!」

6. 结果处理:自动加前缀假装在工作

tsx

recognition.onresult = (event: any) => {
        const transcript = event.results[0][0].transcript;
        onResult(transcript);
        setIsListening(false);
        setRetryCount(0);
    };

  • 文字魔术:语音输入「傻逼需求」→ 显示「会议纪要:需优化需求」
  • 数据安全interimResults: false防止中间结果泄露

7. 错误处理:甩锅指南(不是)

tsx

 recognition.onerror = (event: any) => {
        console.error('语音识别错误:', event.error);

        if (event.error === 'network') {
            if (retryCount < maxRetries && checkNetworkConnection()) {
                setRetryCount((prev) => prev + 1);
                setTimeout(() => {
                    recognition.start();
                }, 1000);
                return;
            }
        }

        setIsListening(false);
        switch (event.error) {
            case 'aborted':
                onError('语音识别被中止,请重试。');
                break;
            case 'no-speech':
                onError('未检测到语音输入,请确保麦克风正常工作并开始说话。');
                break;
            case 'audio-capture':
                onError('无法捕获音频,请检查麦克风是否连接并授予浏览器权限。');
                break;
            case 'not-allowed':
                onError('麦克风权限被拒绝,请允许浏览器访问麦克风。');
                break;
            case 'network':
                onError(`网络连接问题,请检查网络后重试。${retryCount >= maxRetries ? '\n已达到最大重试次数,请稍后再试。' : ''}`);
                break;
            case 'language-not-supported':
                onError('当前语言不被支持,请尝试其他语言。');
                break;
            case 'service-not-allowed':
                onError('浏览器不允许使用语音识别服务,请尝试其他浏览器。');
                break;
            default:
                onError('语音识别发生未知错误,请重试。');
                break;
        }
        setRetryCount(0);
    };

  • 甩锅话术:老板问卡顿,你:「公司网又崩了,我用 Edge 都救不了!」
  • 重试逻辑:失败 3 次后显示「已达最大摸鱼次数」,逼你换姿势摸

三、组件实战:工位物理开关设计

tsx

<div onClick={() => {
                    if (!isListening) {
                        startSpeechRecognition()
                    } else {
                        stopSpeechRecognition()
                    }
                }}>
                    <Microphone1Icon size="22px" style={{ color: 'black' }} />
                </div>

  • 视觉欺骗:绿色表示搬砖,红色表示摸鱼(老板以为在做状态提示)
  • 交互细节:点击时震动反馈(模拟机械键盘,增加摸鱼仪式感)

四、完整代码菜单:复制即用的摸鱼套装

📂 useSpeechRecognition.ts(带逐行注释)

tsx

import { useState } from 'react';

// 定义语音识别的配置接口
interface SpeechRecognitionOptions {
    onResult: (transcript: string) => void; // 语音识别成功时的回调函数
    onError: (error: string) => void; // 语音识别失败时的回调函数
}

// 自定义 Hook:useSpeechRecognition
const useSpeechRecognition = ({ onResult, onError }: SpeechRecognitionOptions) => {
    const [isListening, setIsListening] = useState<boolean>(false); // 是否正在监听语音
    const [retryCount, setRetryCount] = useState<number>(0); // 重试次数
    const maxRetries = 3; // 最大重试次数

    // 获取浏览器的语音识别对象
    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;

    // 如果浏览器不支持语音识别,直接返回错误
    if (!SpeechRecognition) {
        onError('当前浏览器不支持语音识别功能,请使用其他浏览器。');
        return {
            isListening: false,
            startSpeechRecognition: () => { },
            stopSpeechRecognition: () => { },
        };
    }

    // 创建语音识别实例
    const recognition = new SpeechRecognition();
    recognition.lang = 'zh-CN'; // 设置语言为中文
    recognition.interimResults = false; // 是否返回临时结果
    recognition.maxAlternatives = 1; // 返回的最大候选结果数量
    recognition.continuous = false; // 是否连续识别

    // 检查网络连接
    const checkNetworkConnection = () => {
        return navigator.onLine;
    };

    // 语音识别成功时的回调
    recognition.onresult = (event: any) => {
        const transcript = event.results[0][0].transcript; // 获取识别结果
        onResult(transcript); // 调用父组件传递的成功回调
        setIsListening(false); // 停止监听
        setRetryCount(0); // 重置重试次数
    };

    // 语音识别失败时的回调
    recognition.onerror = (event: any) => {
        console.error('语音识别错误:', event.error);

        // 如果是网络错误,尝试重试
        if (event.error === 'network') {
            if (retryCount < maxRetries && checkNetworkConnection()) {
                setRetryCount((prev) => prev + 1); // 增加重试次数
                setTimeout(() => {
                    recognition.start(); // 重试语音识别
                }, 1000);
                return;
            }
        }

        setIsListening(false); // 停止监听
        // 根据错误类型调用不同的错误回调
        switch (event.error) {
            case 'aborted':
                onError('语音识别被中止,请重试。');
                break;
            case 'no-speech':
                onError('未检测到语音输入,请确保麦克风正常工作并开始说话。');
                break;
            case 'audio-capture':
                onError('无法捕获音频,请检查麦克风是否连接并授予浏览器权限。');
                break;
            case 'not-allowed':
                onError('麦克风权限被拒绝,请允许浏览器访问麦克风。');
                break;
            case 'network':
                onError(`网络连接问题,请检查网络后重试。${retryCount >= maxRetries ? '\n已达到最大重试次数,请稍后再试。' : ''}`);
                break;
            case 'language-not-supported':
                onError('当前语言不被支持,请尝试其他语言。');
                break;
            case 'service-not-allowed':
                onError('浏览器不允许使用语音识别服务,请尝试其他浏览器。');
                break;
            default:
                onError('语音识别发生未知错误,请重试。');
                break;
        }
        setRetryCount(0); // 重置重试次数
    };

    // 语音识别结束时的回调
    recognition.onend = () => {
        if (isListening) {
            setIsListening(false); // 停止监听
            setRetryCount(0); // 重置重试次数
        }
    };

    // 启动语音识别
    const startSpeechRecognition = () => {
        if (!isListening) {
            // 检查网络连接
            if (!checkNetworkConnection()) {
                onError('无网络连接,请检查网络后重试。');
                return;
            }
            setRetryCount(0); // 重置重试次数
            try {
                recognition.start(); // 启动语音识别
                setIsListening(true); // 设置为正在监听
            } catch (error) {
                console.error('语音识别启动失败:', error);
                onError('语音识别启动失败,请重试。');
            }
        }
    };

    // 停止语音识别
    const stopSpeechRecognition = () => {
        if (isListening) {
            try {
                recognition.stop(); // 停止语音识别
                setIsListening(false); // 设置为未监听
            } catch (error) {
                console.error('语音识别停止失败:', error);
                onError('语音识别停止失败,请重试。');
            }
        }
    };

    // 语音识别启动时的回调
    recognition.onstart = () => {
        console.log('语音识别已启动');
    };

    // 检测到声音时的回调
    recognition.onsoundstart = () => {
        console.log('检测到声音');
    };

    // 声音结束时的回调
    recognition.onsoundend = () => {
        console.log('声音结束');
    };

    // 返回状态和方法
    return {
        isListening, // 是否正在监听
        startSpeechRecognition, // 启动语音识别
        stopSpeechRecognition, // 停止语音识别
    };
};

export default useSpeechRecognition;

📂 App.tsx(工位实战)

tsx

import useSpeechRecognition from './SpeechRecognitionModule'

    const { isListening, startSpeechRecognition, stopSpeechRecognition } = useSpeechRecognition({
        onResult: (transcript: any) => {
            setMessage((val) => val + transcript);
        },
        onError: (error: any) => {
            NotificationPlugin.error({
                title: '语音识别错误',
                content: error,
            });
        },
    });

{/* 语音识别模块 */}
            <div onClick={() => {
                if (!isListening) {
                    startSpeechRecognition()
                } else {
                    stopSpeechRecognition()
                }
            }}>
                <Microphone1Icon size="22px" style={{ color: 'black' }} />
            </div>

五、摸鱼注意事项:保命指南

  1. Edge 设置:关闭「语音服务个性化」,防止摸鱼语录被微软收录
  2. 物理保护:给麦克风按钮贴「调试按钮」标签,老板问就说在测功能
  3. 敏感词过滤:在onResult中加入text.replace(/傻逼/g, '**'),防止社死
  4. 快捷键:绑定Ctrl+Shift+M启动摸鱼,老板来时一键切换(需配合输入法)

六、总结:Edge,打工人最后的摸鱼净土

当你用 Edge 语音输入「老板,这个需求我再优化下」(内心:优化个*),用本地识别避免隐私泄露,用幽默的错误提示化解尴尬 ——
请记住:这不是普通的 Hook,是用代码构建的「职场安全系统」。

彩蛋:在 Edge 地址栏输入edge://settings/privacy/speech,可以查看语音识别的「摸鱼历史」(建议每周清空)

(完)

(作者:工位摸鱼工程师,擅长用语音识别写周报,Edge 浏览器终身荣誉会员)

💡 最后警告:请勿在代码中写console.log('****'),Edge 的本地识别会直接听懂...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值