AI 音频产品开发模板及流程(一)

发布于:2025-07-24 ⋅ 阅读:(28) ⋅ 点赞:(0)

1. 准备工作

前提条件

构建内容

您可以利用面板小程序开发构建出一个基于 Ray 框架的 AI 音频设备面板,并实现以下功能:

  • 面对面翻译:选择好需要互转的语言,使用不同语言的双方对话时,App 会自动断句并转写、翻译,设备自动播放翻译结果。
  • 同声传译:设置输入语言和翻译语言,点击开始后 App 会自动进行断句,转写文字并进行翻译。
  • 现场录音:将耳机等拾音设备放置在桌面上,点击开始录音,就会自动录下现场声音,结束后可以进行转写和 AI 总结。
  • 转录和 AI 总结:将音频内容转换为文字,AI 根据模板总结内容,并生成 Markdown 格式文本。

所需条件

  • 智能生活 App
  • Tuya MiniApp IDE
  • NVM 及 Node 开发环境(建议使用 18.x 系列版本)
  • Yarn 依赖管理工具

详见 面板小程序 > 搭建环境

2. 创建产品

首先需要创建一个产品,定义产品有哪些功能点,然后再在面板中一一实现这些功能点。

注册登录 涂鸦开发者平台,并在平台创建产品:

  1. 单击页面左侧 产品 > 产品开发,在 产品开发 页面单击 创建产品

  1. 在 标准类目 下选择 影音穿戴 > AI 耳机

  1. 选择 智能化方式 和 产品方案,完善产品信息,单击 创建产品

  1. 在 添加标准功能 页面,根据实际需求选择对应的功能点,单击 确定

🎉 完成以上步骤后,您已成功创建了一个支持 AI 音频实时、离线转录的设备产品。

3. 创建项目

开发者平台创建面板小程序

面板小程序的开发在 小程序开发者 平台上进行操作,首先请前往 小程序开发者平台 完成平台的注册登录。

IDE 基于模板创建项目工程

打开 IDE 创建一个基于 AI 耳机模版 的 AI 音频面板小程序项目,需要在 Tuya MiniApp IDE 上进行操作。

4. 关键能力依赖

  • App 版本
    • 智能生活 v6.3.0 及以上版本
  • Kit 依赖
    • BaseKit:v3.0.6
    • MiniKit:v3.0.1
    • DeviceKit:v4.14.0
    • BizKit:v4.2.0
    • WearKit:v1.1.6
    • baseversion:v2.27.0
  • 组件依赖
    • @ray-js/ray^1.7.14

5. 面对面翻译

  • 实现现场跨语言交流,打破语言壁垒,让不同语言用户可以顺畅沟通。
  • 自动断句、转写和翻译,提高交流效率。
  • 翻译结果可由设备自动播放,沟通体验更自然。
  • 支持多语言互转,适用场景广泛,提升产品智能化和国际化能力。

功能展示

代码片段

  // 开始录音
  const handleStartRecord = useCallback(
    (type: 'left' | 'right') => {
      const startRecordFn = async (type: 'left' | 'right') => {
        // 需要设备在线
        if (!isOnline) return;
        try {
          showLoading({ title: '' });
          const config: any = {
            // 录音类型,0:呼叫、1:会议、2:同声传译、3:面对面翻译
            recordType: 3,
            // DP 控制超时时间,单位秒
            controlTimeout: 5,
            // 灌流超时时间,单位秒
            dataTimeout: 10,
            // 0:文件转写、1:实时转写
            transferType: 1,
            // 是否需要翻译
            needTranslate: true,
            // 输入语言
            originalLanguage: type === 'left' ? leftLanguage : rightLanguage,
            // 输出语言
            targetLanguage: type === 'left' ? rightLanguage : leftLanguage,
            // 智能体 ID,后面具体根据提供的 SDK 获取 agentId。
            agentId: '',
            // 录音通道,0:BLE、1:Bt、2:micro
            recordChannel: isCardStyle || isDevOnline === false ? 2 : 1,
            // 0:代表左耳、1:代表右耳
            f2fChannel: type === 'left' ? 0 : 1,
            // TTS 流编码方式,通过编码后将流写入到耳机设备,0:opus_silk、1:opus_celt
            ttsEncode: isOpusCelt ? 1 : 0,
            // 是否需要 TTS
            needTts: true,
          };
          await tttStartRecord(
            {
              deviceId,
              config,
            },
            true
          );
          setActiveType(type);
          hideLoading();
          setIntervals(1000);
          lastTimeRef.current = Date.now();
        } catch (error) {
          ty.showToast({
            title: Strings.getLang('error_simultaneous_recording_start'),
            icon: 'error',
          });
          hideLoading();
        }
      };
      ty.authorize({
        scope: 'scope.record',
        success: () => {
          startRecordFn(type);
        },
        fail: e => {
          ty.showToast({ title: Strings.getLang('no_record_permisson'), icon: 'error' });
        },
      });
    },
    [deviceId, isOnline, rightLanguage, leftLanguage]
  );
  // 暂停
  const handlePauseRecord = async () => {
    try {
      const d = await tttPauseRecord(deviceId);
      setActiveType('');
      console.log('pauseRecord', d);
      setIntervals(undefined);
    } catch (error) {
      console.log('handlePauseRecord fail', error);
    }
  };
  // 继续录音
  const handleResumeRecord = async () => {
    if (!isOnline) return;
    try {
      const d = await tttResumeRecord(deviceId);
      setIntervals(1000);
      lastTimeRef.current = Date.now();
    } catch (error) {
      console.log('handleResumeRecord fail', error);
    }
  };
  // 停止录音
  const handleStopRecord = async () => {
    try {
      showLoading({ title: '' });
      const d = await tttStopRecord(deviceId);
      hideLoading();
      console.log('stopRecord', d);
      backToHome(fromType);
    } catch (error) {
      hideLoading();
    }
  };
  // 监听 ASR 和翻译返回
  onRecordTransferRealTimeRecognizeStatusUpdateEvent(handleRecrodChange);
  // 处理 ASR 和翻译
  const handleRecrodChange = d => {
    try {
      const {
        // 阶段,0:任务、4:ASR、5:翻译、6:skill、7:TTS
        phase,
        // 阶段状态,0:未开启、1:进行中、2:结束、3:取消
        status,
        requestId,
        // 转写的文本
        text,
        // 错误码
        errorCode,
      } = d;
      // ASR 阶段接收并实时更新对应 requestId 文本
      if (phase === 4) {
        const currTextItemIdx = currTextListRef.current.findIndex(item => item.id === requestId);
        if (currTextItemIdx > -1) {
          const newList = currTextListRef.current.map(item =>
            item.id === requestId ? { ...item, text } : item
          );
          currTextListRef.current = newList;
          setTextList(newList);
        } else {
          if (!text) return;
          const newList = [
            ...currTextListRef.current,
            {
              id: requestId,
              text,
            },
          ];
          currTextListRef.current = newList;
          setTextList(newList);
        }
        // 翻译返回阶段,接收并展示 status=2 即已完成翻译的
      } else if (phase === 5 && status === 2) {
        let resText = '';
        if (text && text !== 'null') {
          if (isJsonString(text)) {
            const textArr = JSON.parse(text);
            const isArr = Array.isArray(textArr);
            // 数字的 string 类型如 111,isJsonString 判断为 json 字符串,会导致 .join 失败
            resText = isArr ? textArr?.join('\n') : textArr;
          } else {
            resText = text;
          }
        }

        if (!resText) {
          return;
        }

        const newList = currTextListRef.current.map(item => {
          return item.id === requestId ? { ...item, text: `${item.text}\n${resText}` } : item;
        });
        currTextListRef.current = newList;
        setTextList(newList);
      }
    } catch (error) {
      console.warn(error);
    }
  };

 AI 音频产品开发模板及流程(二)


网站公告

今日签到

点亮在社区的每一天
去签到