鸿蒙5 AI语音备忘录开发实战:语音转写与多设备同步 原创

进修的泡芙
发布于 2025-6-20 12:25
浏览
0收藏

鸿蒙5 AI语音备忘录开发实战:语音转写与多设备同步

一、项目概述与架构设计

本AI语音备忘录应用基于鸿蒙5的AI能力与分布式技术实现,主要功能包括:
语音实时转文字(ASR)

备忘录内容跨设备同步

语音指令控制

多设备协同编辑

技术架构图

┌─────────────┐ ┌─────────────┐ ┌─────────────┐
手机设备 │ │ 平板设备 │ │ 手表设备 │

┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │

│ 语音输入 │─┼───▶│ │ 文本显示 │ │ │ │ 快捷查看 │ │

└────────┘ │ │ └────────┘ │ │ └────────┘ │

└───────┬─────┘ └───────┬─────┘ └───────┬─────┘
│ │

    └─────────┬────────┴─────────┬────────┘

      ┌───────▼───────┐   ┌───────▼───────┐

分布式数据服务 │ │ AI语音服务 │

      └───────────────┘   └───────────────┘

二、核心代码实现
语音识别服务封装

// VoiceService.ets
import asr from ‘@ohos.ai.asr’;
import distributedData from ‘@ohos.data.distributedData’;

export class VoiceService {
private asrEngine: asr.AsrEngine;
private kvStore: distributedData.KVStore;
private readonly STORE_ID = ‘voice_memo_store’;

async init() {
// 初始化ASR引擎
const config: asr.AsrConfig = {
language: ‘zh-CN’,
feature: asr.AsrFeature.FEATURE_WORD_FLUX
};
this.asrEngine = await asr.createAsrEngine();
await this.asrEngine.init(config);

// 初始化分布式数据
const kvManager = await distributedData.createKVManager({
  bundleName: 'com.example.voicememo'
});
this.kvStore = await kvManager.getKVStore(this.STORE_ID, {
  createIfMissing: true,
  autoSync: true
});

async startRecording(callback: (text: string) => void) {

// 开始录音并实时转写
await this.asrEngine.on('result', (result: asr.AsrResult) => {
  if (result.text) {
    callback(result.text);
    this.syncTranscript(result.text);

});

await this.asrEngine.start();

async stopRecording() {

await this.asrEngine.stop();

private async syncTranscript(text: string) {

try {
  const memo = {
    text,
    timestamp: new Date().getTime(),
    deviceId: deviceInfo.deviceId
  };
  await this.kvStore.put('current_memo', JSON.stringify(memo));

catch (err) {

  console.error('Sync transcript failed:', err);

}

subscribeTranscriptChanges(callback: (text: string) => void) {
this.kvStore.on(‘dataChange’, distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, (changes) => {
changes.forEach(change => {
if (change.key === ‘current_memo’) {
const memo = JSON.parse(change.value);
if (memo.deviceId !== deviceInfo.deviceId) {
callback(memo.text);
}

  });
});

}

备忘录主界面实现

// MemoPage.ets
@Entry
@Component
struct MemoPage {
@State currentText: string = ‘’;
@State memoList: Array<MemoItem> = [];
@State isRecording: boolean = false;
@State connectedDevices: Array<DeviceInfo> = [];

private voiceService: VoiceService = new VoiceService();
private deviceManager: DeviceManager = new DeviceManager();

aboutToAppear() {
this.voiceService.init();
this.voiceService.subscribeTranscriptChanges(this.handleTranscriptChange.bind(this));
this.deviceManager.startDiscovery();
build() {

Column() {
  // 设备连接状态
  DeviceStatusBar({ devices: this.connectedDevices })
  
  // 语音输入区域
  VoiceInputPanel({
    isRecording: this.isRecording,
    onStart: this.startRecording.bind(this),
    onStop: this.stopRecording.bind(this)
  })
  
  // 实时转写文本
  Scroll() {
    Text(this.currentText)
      .fontSize(16)
      .padding(10)

.height(‘40%’)

  // 历史备忘录列表
  MemoList({
    items: this.memoList,
    onSelect: this.selectMemo.bind(this)
  })

}

private async startRecording() {
this.isRecording = true;
await this.voiceService.startRecording((text) => {
this.currentText = text;
});
private async stopRecording() {

this.isRecording = false;
await this.voiceService.stopRecording();
this.saveMemo();

private handleTranscriptChange(text: string) {

this.currentText = text;

private saveMemo() {

if (this.currentText.trim()) {
  this.memoList = [...this.memoList, {
    id: Date.now().toString(),
    text: this.currentText,
    timestamp: new Date()
  }];
  this.currentText = '';

}

// 其他方法…

多设备同步控制

// DeviceManager.ets
import deviceManager from ‘@ohos.distributedHardware.deviceManager’;

export class DeviceManager {
private deviceList: Array<DeviceInfo> = [];

async startDiscovery() {
try {
const manager = await deviceManager.createDeviceManager(‘com.example.voicememo’);

  manager.on('deviceStateChange', (data) => {
    this.handleDeviceChange(data);
  });
  
  manager.startDeviceDiscovery(['voice_memo_sync']);

catch (err) {

  console.error('Device discovery failed:', err);

}

private handleDeviceChange(data: deviceManager.DeviceStateChangeData) {
if (data.action === 0) { // 设备上线
if (!this.deviceList.some(d => d.deviceId === data.device.deviceId)) {
this.deviceList = […this.deviceList, data.device];
AppStorage.setOrCreate(‘connectedDevices’, this.deviceList);
} else if (data.action === 1) { // 设备下线

  this.deviceList = this.deviceList.filter(d => d.deviceId !== data.device.deviceId);
  AppStorage.setOrCreate('connectedDevices', this.deviceList);

}

async syncToDevice(deviceId: string, memo: MemoItem) {
try {
const kvManager = await distributedData.createKVManager({
bundleName: ‘com.example.voicememo’
});
const kvStore = await kvManager.getKVStore(‘memo_sync_store’);

  await kvStore.put(memo_${memo.id}, JSON.stringify({
    ...memo,
    sourceDevice: deviceInfo.deviceId,
    targetDevice: deviceId
  }));

catch (err) {

  console.error('Sync memo failed:', err);

}

三、关键技术创新点
实时语音转写优化

// 语音识别参数优化
const optimizedConfig: asr.AsrConfig = {
language: ‘zh-CN’,
feature: asr.AsrFeature.FEATURE_WORD_FLUX,
audioFormat: {
sampleRate: 16000,
channelCount: 1,
encoding: asr.AudioEncoding.ENCODING_PCM_16BIT
},
vad: {
enable: true,
frontWaitTime: 300,
backWaitTime: 500
};

// 语音端点检测
this.asrEngine.on(‘vadChange’, (state: asr.VadState) => {
if (state === asr.VadState.VAD_STATE_VOICE_END) {
this.saveCurrentMemo();
});

多设备冲突解决策略

// 冲突解决算法
private resolveMemoConflict(local: MemoItem, remote: MemoItem): MemoItem {
// 策略1: 时间戳优先
if (remote.timestamp > local.timestamp) {
return remote;
// 策略2: 内容长度优先

if (remote.text.length > local.text.length) {
return remote;
return local;

// 在数据变更监听中应用

this.kvStore.on(‘dataChange’, (changes) => {
changes.forEach(change => {
if (change.key.startsWith(‘memo_’)) {
const remoteMemo = JSON.parse(change.value);
const localMemo = this.findMemo(remoteMemo.id);

  if (localMemo) {
    const resolved = this.resolveMemoConflict(localMemo, remoteMemo);
    this.updateMemo(resolved);

else {

    this.addMemo(remoteMemo);

}

});
});

语音指令识别

// 语音命令处理
private processVoiceCommand(text: string) {
const commands = [
pattern: /保存备忘录/, action: this.saveMemo.bind(this) },

pattern: /清空内容/, action: this.clearText.bind(this) },

pattern: /同步到平板/, action: this.syncToTablet.bind(this) }

];

for (const cmd of commands) {
if (cmd.pattern.test(text)) {
cmd.action();
break;
}

// 在录音回调中添加

this.voiceService.startRecording((text) => {
this.currentText = text;
this.processVoiceCommand(text);
});

四、性能优化方案
音频处理优化

// 音频缓冲设置
const audioOptions = {
bufferSize: 8192, // 8KB缓冲区
sampleRate: 16000,
channels: 1
};

// 在录音前配置
audio.createAudioCapturer(audioOptions, (err, capturer) => {
if (!err) {
this.audioCapturer = capturer;
});

网络自适应同步

// 根据网络状况调整同步策略
network.getDefaultNet().on(‘netCapabilitiesChange’, (capabilities) => {
const isWifi = capabilities.bearerTypes.includes(network.NetBearType.BEARER_WIFI);

this.kvStore.setSyncParam(‘current_memo’, isWifi); // 仅在WiFi下自动同步
this.syncInterval = isWifi ? 1000 : 5000; // 调整同步间隔
});

设备资源适配

// 根据设备类型调整功能
private setupDeviceSpecificFeatures() {
switch(deviceInfo.deviceType) {
case ‘phone’:
this.enableVoiceInput(true);
break;
case ‘watch’:
this.enableVoiceInput(false);
this.loadCompactUI();
break;
default:
this.enableFullFeatures();
}

五、完整示例代码
语音输入面板组件

// VoiceInputPanel.ets
@Component
struct VoiceInputPanel {
@Prop isRecording: boolean;
@State voiceLevel: number = 0;

build() {
Column() {
if (this.isRecording) {
// 录音中状态
Row() {
Image(‘mic_on.png’)
.width(40)
.height(40)

      // 音量波动动画
      ForEach(Array.from({length: 5}), (_, i) => {
        Rect()
          .width(4)
          .height(10 + this.voiceLevel * i)
          .fill(Color.Blue)
          .margin(2)
      })

.animation({ duration: 200, iterations: -1 })

    Button('停止录音')
      .onClick(() => this.onStop())

else {

    // 待机状态
    Button('开始录音', { type: ButtonType.Capsule })
      .onClick(() => this.onStart())

}

.padding(20)

private updateVoiceLevel() {

setInterval(() => {
  if (this.isRecording) {
    this.voiceLevel = Math.random() * 10;

}, 100);

}

备忘录列表组件

// MemoList.ets
@Component
struct MemoList {
@Prop items: Array<MemoItem>;
@State selectedId: string = ‘’;

build() {
List() {
ForEach(this.items, (item) => {
ListItem() {
MemoListItem({
memo: item,
isSelected: this.selectedId === item.id
})
.onClick(() => {
this.selectedId = item.id;
this.onSelect(item);
})
})

.divider({ strokeWidth: 1, color: ‘#F1F1F1’ })

}

@Component
struct MemoListItem {
@Prop memo: MemoItem;
@Prop isSelected: boolean;

build() {
Row() {
Column() {
Text(this.memo.text)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })

    Text(this.formatDate(this.memo.timestamp))
      .fontSize(12)
      .opacity(0.6)

.layoutWeight(1)

  if (this.isSelected) {
    Image('checked.png')
      .width(20)
      .height(20)

}

.padding(10)
.backgroundColor(this.isSelected ? '#E6F7FF' : Color.White)

}

六、项目部署与测试
权限配置

在module.json5中添加:

"requestPermissions": [
"name": "ohos.permission.MICROPHONE"

  },
"name": "ohos

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐