当前位置: 首页 > news >正文

【鸿蒙开发】第二十四章 AI - Core Speech Kit(基础语音服务)

目录

1 简介

1.1 场景介绍

1.2 约束与限制

2 文本转语音

2.1 场景介绍

2.2 约束与限制

2.3 开发步骤

2.4 设置播报策略

2.4.1 设置单词播报方式 

2.4.2 设置数字播报策略

2.4.3 插入静音停顿

2.4.4 指定汉字发音

2.5 开发实例

3 语音识别

3.1 场景介绍

3.2 约束与限制

3.3 开发步骤

3.4 开发实例


1 简介

Core Speech Kit(基础语音服务)集成了语音类基础AI能力,包括文本转语音(TextToSpeech)语音识别(SpeechRecognizer)能力,便于用户与设备进行互动,实现将实时输入的语音与文本之间相互转换。

1.1 场景介绍

  • 文本转语音:将一段不超过10000字符的文本合成为语音并进行播报。
  • 语音识别:将一段音频信息(短语音模式不超过60s,长语音模式不超过8h)转换为文本,可以将pcm音频文件或者实时语音转换为文字。

1.2 约束与限制

AI能力

约束

文本转语音

  • 支持的语种类型:中文。(简体中文、繁体中文、中文语境下的英文)
  • 支持的音色类型:聆小珊女声音色。
  • 文本长度:不超过10000字符。

语音识别

  • 支持的语种类型:中文普通话。
  • 支持的模型类型:离线。
  • 语音时长:短语音模式不超过60s,长语音模式不超过8h。

2 文本转语音

Core Speech Kit支持将一篇不超过10000字符的中文文本(简体中文、繁体中文、数字、中文语境下的英文)合成为语音,并以聆小珊女声音色中文播报。

开发者可对播报的策略进行设置,包括单词播报数字播报静音停顿汉字发音策略

2.1 场景介绍

手机/平板等设备在无网状态下,系统应用无障碍(屏幕朗读)接入文本转语音能力,为视障人士不方便阅读场景提供播报能力。

2.2 约束与限制

该能力当前不支持模拟器

2.3 开发步骤

1.   在使用文本转语音时,将实现文本转语音相关的类添加至工程。

import { textToSpeech } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';

 2.   调用createEngine接口,创建textToSpeechEngine实例。createEngine接口提供了两种调用形式,当前以其中一种作为示例,其他方式可参考API参考。

let ttsEngine: textToSpeech.TextToSpeechEngine;// 设置创建引擎参数
let extraParam: Record<string, Object> = {"style": 'interaction-broadcast', "locate": 'CN', "name": 'EngineName'};
let initParamsInfo: textToSpeech.CreateEngineParams = {language: 'zh-CN',person: 0,online: 1,extraParams: extraParam
};// 调用createEngine方法
textToSpeech.createEngine(initParamsInfo, (err: BusinessError, textToSpeechEngine: textToSpeech.TextToSpeechEngine) => {if (!err) {console.info('Succeeded in creating engine');// 接收创建引擎的实例ttsEngine = textToSpeechEngine;} else {console.error(`Failed to create engine. Code: ${err.code}, message: ${err.message}.`);}
});

3. 得到TextToSpeechEngine实例对象后,实例化SpeakParams对象、SpeakListener对象,并传入待合成及播报的文本originalText,调用speak接口进行播报。

// 设置speak的回调信息
let speakListener: textToSpeech.SpeakListener = {// 开始播报回调onStart(requestId: string, response: textToSpeech.StartResponse) {console.info(`onStart, requestId: ${requestId} response: ${JSON.stringify(response)}`);},// 合成完成及播报完成回调onComplete(requestId: string, response: textToSpeech.CompleteResponse) {console.info(`onComplete, requestId: ${requestId} response: ${JSON.stringify(response)}`);},// 停止播报回调onStop(requestId: string, response: textToSpeech.StopResponse) {console.info(`onStop, requestId: ${requestId} response: ${JSON.stringify(response)}`);},// 返回音频流onData(requestId: string, audio: ArrayBuffer, response: textToSpeech.SynthesisResponse) {console.info(`onData, requestId: ${requestId} sequence: ${JSON.stringify(response)} audio: ${JSON.stringify(audio)}`);},// 错误回调onError(requestId: string, errorCode: number, errorMessage: string) {console.error(`onError, requestId: ${requestId} errorCode: ${errorCode} errorMessage: ${errorMessage}`);}
};
// 设置回调
ttsEngine.setListener(speakListener);
let originalText: string = 'Hello HarmonyOS';
// 设置播报相关参数
let extraParam: Record<string, Object> = {"queueMode": 0, "speed": 1, "volume": 2, "pitch": 1, "languageContext": 'zh-CN',  
"audioType": "pcm", "soundChannel": 3, "playType": 1 };
let speakParams: textToSpeech.SpeakParams = {requestId: '123456', // requestId在同一实例内仅能用一次,请勿重复设置extraParams: extraParam
};
// 调用播报方法
// 开发者可以通过修改speakParams主动设置播报策略
ttsEngine.speak(originalText, speakParams);

4. (可选)当需要停止合成及播报时,可调用stop接口。

ttsEngine.stop();

5. (可选)当需要查询文本转语音服务是否处于忙碌状态时,可调用isBusy接口。

ttsEngine.isBusy();

6.(可选)当需要查询支持的语种音色信息时,可调用listVoices接口。

listVoices接口提供了两种调用形式,当前以其中一种作为示例,其他方式可参考API参考。

// 在组件中声明并初始化字符串voiceInfo
@State voiceInfo: string = "";// 设置查询相关参数
let voicesQuery: textToSpeech.VoiceQuery = {requestId: '12345678', // requestId在同一实例内仅能用一次,请勿重复设置online: 1
};
// 调用listVoices方法,以callback返回
ttsEngine.listVoices(voicesQuery, (err: BusinessError, voiceInfo: textToSpeech.VoiceInfo[]) => {if (!err) {// 接收目前支持的语种音色等信息this.voiceInfo = JSON.stringify(voiceInfo);console.info(`Succeeded in listing voices, voiceInfo is ${this.voiceInfo}`);} else {console.error(`Failed to list voices. Code: ${err.code}, message: ${err.message}`);}
});

2.4 设置播报策略

由于不同场景下,模型自动判断所选择的播报策略可能与实际需求不同,此章节提供对于播报策略进行主动设置的方法。

说明

以下取值说明均为有效取值,若所使用的数值在有效取值之外则播报结果可能与预期不符,并产生错误的播报结果。

2.4.1 设置单词播报方式 

文本格式:[hN] (N=0/1/2)

N取值说明:

取值

说明

0

智能判断单词播放方式。默认值为0。

1

逐个字母进行播报。

2

以单词方式进行播报。

文本示例:

"hello[h1] world"

hello使用单词发音,world及后续单词将会逐个字母进行发音。

2.4.2 设置数字播报策略

格式:[nN] (N=0/1/2)

N取值说明:

取值

说明

0

智能判断数字处理策略。默认值为0。

1

作为号码逐个数字播报。

2

作为数值播报。超过18位数字不支持,自动按逐个数字进行播报。

文本示例

"[n2]123[n1]456[n0]"

其中,123将会按照数值播报,456则会按照号码播报,而后的文本中的数字,均会自动判断

2.4.3 插入静音停顿

格式:[pN]

描述:N为无符号整数,单位为ms

文本示例:

"你好[p500]小艺"

该句播报时,将会在“你好”后插入500ms的静音停顿。

2.4.4 指定汉字发音

汉字声调用后接一位数字1~5分别表示阴平、阳平、上声、去声和轻声5个声调。

格式:[=MN]

描述:M表示拼音,N表示声调。

N取值说明:

取值

说明

1

阴平

2

阳平

3

上声

4

去声

5

轻声

文本示例:

"着[=zhuo2]手"

2.5 开发实例

点击按钮,播报一段文本。

import { textToSpeech } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';let ttsEngine: textToSpeech.TextToSpeechEngine;
@Entry
@Component
struct Index {@State createCount: number = 0;@State result: boolean = false;@State voiceInfo: string = "";@State text: string = "";@State textContent: string = "";@State utteranceId: string = "123456";@State originalText: string = "\n\t\t古人学问无遗力,少壮工夫老始成;\n\t\t" +"纸上得来终觉浅,绝知此事要躬行。\n\t\t";@State illegalText: string = "";build() {Column() {Scroll() {Column() {TextArea({ placeholder: 'Please enter tts original text', text: `${this.originalText}` }).margin(20).focusable(false).border({ width: 5, color: 0x317AE7, radius: 10, style: BorderStyle.Dotted }).onChange((value: string) => {this.originalText = value;console.info(`original text: ${this.originalText}`);})Button() {Text("CreateEngineByCallback").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {this.createCount++;console.info(`CreateTtsEngine:createCount:${this.createCount}`);this.createByCallback();})Button() {Text("speak").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {this.createCount++;this.speak();})Button() {Text("listVoicesCallback").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {this.listVoicesCallback();})Button() {Text("stop").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {// 停止播报console.info("Stop button clicked.");ttsEngine.stop();})Button() {Text("isBusy").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {// 查询播报状态let isBusy = ttsEngine.isBusy();console.info(`isBusy: ${isBusy}`);})Button() {Text("shutdown").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AA7").width("80%").height(50).margin(10).onClick(() => {// 释放引擎ttsEngine.shutdown();})}.layoutWeight(1)}.width('100%').height('100%')}}// 创建引擎,通过callback形式返回private createByCallback() {// 设置创建引擎参数let extraParam: Record<string, Object> = {"style": 'interaction-broadcast', "locate": 'CN', "name": 'EngineName'};let initParamsInfo: textToSpeech.CreateEngineParams = {language: 'zh-CN',person: 0,online: 1,extraParams: extraParam};// 调用createEngine方法textToSpeech.createEngine(initParamsInfo, (err: BusinessError, textToSpeechEngine: textToSpeech.TextToSpeechEngine) => {if (!err) {console.info('Succeeded in creating engine.');// 接收创建引擎的实例ttsEngine = textToSpeechEngine;} else {console.error(`Failed to create engine. Code: ${err.code}, message: ${err.message}.`);}});};// 调用speak播报方法private speak() {let speakListener: textToSpeech.SpeakListener = {// 开始播报回调onStart(requestId: string, response: textToSpeech.StartResponse) {console.info(`onStart, requestId: ${requestId} response: ${JSON.stringify(response)}`);},// 完成播报回调onComplete(requestId: string, response: textToSpeech.CompleteResponse) {console.info(`onComplete, requestId: ${requestId} response: ${JSON.stringify(response)}`);}, // 停止播报完成回调,调用stop方法并完成时会触发此回调onStop(requestId: string, response: textToSpeech.StopResponse) {console.info(`onStop, requestId: ${requestId} response: ${JSON.stringify(response)}`);},// 返回音频流onData(requestId: string, audio: ArrayBuffer, response: textToSpeech.SynthesisResponse) {console.info(`onData, requestId: ${requestId} sequence: ${JSON.stringify(response)} audio: ${JSON.stringify(audio)}`);},// 错误回调,播报过程发生错误时触发此回调onError(requestId: string, errorCode: number, errorMessage: string) {console.error(`onError, requestId: ${requestId} errorCode: ${errorCode} errorMessage: ${errorMessage}`);}};// 设置回调ttsEngine.setListener(speakListener);// 设置播报相关参数let extraParam: Record<string, Object> = {"queueMode": 0, "speed": 1, "volume": 2, "pitch": 1, "languageContext": 'zh-CN', "audioType": "pcm", "soundChannel": 3, "playType":1}let speakParams: textToSpeech.SpeakParams = {requestId: '123456-a', // requestId在同一实例内仅能用一次,请勿重复设置extraParams: extraParam};// 调用speak播报方法ttsEngine.speak(this.originalText, speakParams);};// 查询语种音色信息,以callback形式返回private listVoicesCallback() {// 设置查询相关参数let voicesQuery: textToSpeech.VoiceQuery = {requestId: '123456-b', // requestId在同一实例内仅能用一次,请勿重复设置online: 1};// 调用listVoices方法,以callback返回语种音色查询结果ttsEngine.listVoices(voicesQuery, (err: BusinessError, voiceInfo: textToSpeech.VoiceInfo[]) => {if (!err) {// 接收目前支持的语种音色等信息this.voiceInfo = JSON.stringify(voiceInfo);console.info(`Succeeded in listing voices, voiceInfo is ${voiceInfo}`);} else {console.error(`Failed to list voices. Code: ${err.code}, message: ${err.message}`);}});};
}

3 语音识别

将一段中文音频信息(中文、中文语境下的英文;短语音模式不超过60s,长语音模式不超过8h)转换为文本,音频信息可以为pcm音频文件或者实时语音

3.1 场景介绍

手机/平板等设备在无网状态下,为听障人士或不方便收听音频场景提供音频转文本能力。

3.2 约束与限制

该能力当前不支持模拟器

3.3 开发步骤

1. 在使用语音识别时,将实现语音识别相关的类添加至工程。

import { speechRecognizer } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';

2. 调用createEngine方法,对引擎进行初始化,并创建SpeechRecognitionEngine实例。

createEngine方法提供了两种调用形式,当前以其中一种作为示例,其他方式可参考API参考。

let asrEngine: speechRecognizer.SpeechRecognitionEngine;
let sessionId: string = '123456';
// 创建引擎,通过callback形式返回
// 设置创建引擎参数
let extraParam: Record<string, Object> = {"locate": "CN", "recognizerMode": "short"};
let initParamsInfo: speechRecognizer.CreateEngineParams = {language: 'zh-CN',online: 1,extraParams: extraParam
};
// 调用createEngine方法
speechRecognizer.createEngine(initParamsInfo, (err: BusinessError, speechRecognitionEngine: speechRecognizer.SpeechRecognitionEngine) => {if (!err) {console.info('Succeeded in creating engine.');// 接收创建引擎的实例asrEngine = speechRecognitionEngine;} else {console.error(`Failed to create engine. Code: ${err.code}, message: ${err.message}.`);}
});

3. 得到SpeechRecognitionEngine实例对象后,实例化RecognitionListener对象,调用setListener方法设置回调,用来接收语音识别相关的回调信息。

// 创建回调对象
let setListener: speechRecognizer.RecognitionListener = {// 开始识别成功回调onStart(sessionId: string, eventMessage: string) {console.info(`onStart, sessionId: ${sessionId} eventMessage: ${eventMessage}`);},// 事件回调onEvent(sessionId: string, eventCode: number, eventMessage: string) {console.info(`onEvent, sessionId: ${sessionId} eventCode: ${eventCode} eventMessage: ${eventMessage}`);},// 识别结果回调,包括中间结果和最终结果onResult(sessionId: string, result: speechRecognizer.SpeechRecognitionResult) {console.info(`onResult, sessionId: ${sessionId} sessionId: ${JSON.stringify(result)}`);},// 识别完成回调onComplete(sessionId: string, eventMessage: string) {console.info(`onComplete, sessionId: ${sessionId} eventMessage: ${eventMessage}`);},// 错误回调,错误码通过本方法返回// 如:返回错误码1002200006,识别引擎正忙,引擎正在识别中// 更多错误码请参考错误码参考onError(sessionId: string, errorCode: number, errorMessage: string) {console.error(`onError, sessionId: ${sessionId} errorCode: ${errorCode} errorMessage: ${errorMessage}`);}
}
// 设置回调
asrEngine.setListener(setListener);

 4. 分别为音频文件转文字和麦克风转文字功能设置开始识别的相关参数,调用startListening方法,开始合成。

// 开始识别
private startListeningForWriteAudio() {// 设置开始识别的相关参数let recognizerParams: speechRecognizer.StartParams = {sessionId: this.sessionId,audioInfo: { audioType: 'pcm', sampleRate: 16000, soundChannel: 1, sampleBit: 16 } //audioInfo参数配置请参考AudioInfo}// 调用开始识别方法asrEngine.startListening(recognizerParams);
};private startListeningForRecording() {let audioParam: speechRecognizer.AudioInfo = { audioType: 'pcm', sampleRate: 16000, soundChannel: 1, sampleBit: 16 }let extraParam: Record<string, Object> = {"recognitionMode": 0,"vadBegin": 2000,"vadEnd": 3000,"maxAudioDuration": 20000}let recognizerParams: speechRecognizer.StartParams = {sessionId: this.sessionId,audioInfo: audioParam,extraParams: extraParam}console.info('startListening start');asrEngine.startListening(recognizerParams);
};

5. 传入音频流,调用writeAudio方法,开始写入音频流。读取音频文件时,开发者需预先准备一个pcm格式音频文件。

let uint8Array: Uint8Array = new Uint8Array();
// 可以通过如下方式获取音频流:1、通过录音获取音频流;2、从音频文件中读取音频流
// 2、从音频文件中读取音频流:demo参考
// 写入音频流,音频流长度仅支持640或1280
asrEngine.writeAudio(sessionId, uint8Array);

6. (可选)当需要查询语音识别服务支持的语种信息,可调用listLanguages方法。

listLanguages方法提供了两种调用形式,当前以其中一种作为示例,其他方式可参考API参考。

// 设置查询相关的参数
let languageQuery: speechRecognizer.LanguageQuery = {sessionId: sessionId
};
// 调用listLanguages方法
asrEngine.listLanguages(languageQuery).then((res: Array<string>) => {console.info(`Succeeded in listing languages, result: ${JSON.stringify(res)}.`);
}).catch((err: BusinessError) => {console.error(`Failed to list languages. Code: ${err.code}, message: ${err.message}.`);
});

7. (可选)当需要结束识别时,可调用finish方法。

// 结束识别
asrEngine.finish(sessionId);

8.(可选)当需要取消识别时,可调用cancel方法。

// 取消识别
asrEngine.cancel(sessionId);

9. (可选)当需要释放语音识别引擎资源时,可调用shutdown方法。

// 释放识别引擎资源
asrEngine.shutdown();

10. 需要在module.json5配置文件中添加ohos.permission.MICROPHONE权限,确保麦克风使用正常。详细步骤可查看声明权限章节。

//...
"requestPermissions": [{"name" : "ohos.permission.MICROPHONE","reason": "$string:reason","usedScene": {"abilities": ["EntryAbility"],"when":"inuse"}}
],
//...

3.4 开发实例

点击按钮,将一段音频信息转换为文本。index.ets文件如下:

import { speechRecognizer } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import AudioCapturer from './AudioCapturer';const TAG = 'CoreSpeechKitDemo';let asrEngine: speechRecognizer.SpeechRecognitionEngine;@Entry
@Component
struct Index {@State createCount: number = 0;@State result: boolean = false;@State voiceInfo: string = "";@State sessionId: string = "123456";private mAudioCapturer = new AudioCapturer();build() {Column() {Scroll() {Column() {Button() {Text("CreateEngineByCallback").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {this.createCount++;hilog.info(0x0000, TAG, `CreateAsrEngine:createCount:${this.createCount}`);this.createByCallback();})Button() {Text("setListener").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {this.setListener();})Button() {Text("startRecording").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {this.startRecording();})Button() {Text("writeAudio").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {this.writeAudio();})Button() {Text("queryLanguagesCallback").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {this.queryLanguagesCallback();})Button() {Text("finish").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {// 结束识别hilog.info(0x0000, TAG, "finish click:-->");asrEngine.finish(this.sessionId);})Button() {Text("cancel").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AE7").width("80%").height(50).margin(10).onClick(() => {// 取消识别hilog.info(0x0000, TAG, "cancel click:-->");asrEngine.cancel(this.sessionId);})Button() {Text("shutdown").fontColor(Color.White).fontSize(20)}.type(ButtonType.Capsule).backgroundColor("#0x317AA7").width("80%").height(50).margin(10).onClick(() => {// 释放引擎asrEngine.shutdown();})}.layoutWeight(1)}.width('100%').height('100%')}}// 创建引擎,通过callback形式返回private createByCallback() {// 设置创建引擎参数let extraParam: Record<string, Object> = {"locate": "CN", "recognizerMode": "short"};let initParamsInfo: speechRecognizer.CreateEngineParams = {language: 'zh-CN',online: 1,extraParams: extraParam};// 调用createEngine方法speechRecognizer.createEngine(initParamsInfo, (err: BusinessError, speechRecognitionEngine:speechRecognizer.SpeechRecognitionEngine) => {if (!err) {hilog.info(0x0000, TAG, 'Succeeded in creating engine.');// 接收创建引擎的实例asrEngine = speechRecognitionEngine;} else {// 无法创建引擎时返回错误码1002200001,原因:语种不支持、模式不支持、初始化超时、资源不存在等导致创建引擎失败// 无法创建引擎时返回错误码1002200006,原因:引擎正在忙碌中,一般多个应用同时调用语音识别引擎时触发// 无法创建引擎时返回错误码1002200008,原因:引擎已被销毁hilog.error(0x0000, TAG, `Failed to create engine. Code: ${err.code}, message: ${err.message}.`);}});}// 查询语种信息,以callback形式返回private queryLanguagesCallback() {// 设置查询相关参数let languageQuery: speechRecognizer.LanguageQuery = {sessionId: '123456'};// 调用listLanguages方法asrEngine.listLanguages(languageQuery, (err: BusinessError, languages: Array<string>) => {if (!err) {// 接收目前支持的语种信息hilog.info(0x0000, TAG, `Succeeded in listing languages, result: ${JSON.stringify(languages)}`);} else {hilog.error(0x0000, TAG, `Failed to create engine. Code: ${err.code}, message: ${err.message}.`);}});};// 开始识别private startListeningForWriteAudio() {// 设置开始识别的相关参数let recognizerParams: speechRecognizer.StartParams = {sessionId: this.sessionId,audioInfo: { audioType: 'pcm', sampleRate: 16000, soundChannel: 1, sampleBit: 16 } //audioInfo参数配置请参考AudioInfo}// 调用开始识别方法asrEngine.startListening(recognizerParams);};private startListeningForRecording() {let audioParam: speechRecognizer.AudioInfo = { audioType: 'pcm', sampleRate: 16000, soundChannel: 1, sampleBit: 16 }let extraParam: Record<string, Object> = {"recognitionMode": 0,"vadBegin": 2000,"vadEnd": 3000,"maxAudioDuration": 20000}let recognizerParams: speechRecognizer.StartParams = {sessionId: this.sessionId,audioInfo: audioParam,extraParams: extraParam}hilog.info(0x0000, TAG, 'startListening start');asrEngine.startListening(recognizerParams);};// 写音频流private async writeAudio() {this.startListeningForWriteAudio();hilog.error(0x0000, TAG, `Failed to read from file. Code`);let ctx = getContext(this);let filenames: string[] = fileIo.listFileSync(ctx.filesDir);if (filenames.length <= 0) {hilog.error(0x0000, TAG, `Failed to read from file. Code`);return;}hilog.error(0x0000, TAG, `Failed to read from file. Code`);let filePath: string = `${ctx.filesDir}/${filenames[0]}`;let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE);try {let buf: ArrayBuffer = new ArrayBuffer(1280);let offset: number = 0;while (1280 == fileIo.readSync(file.fd, buf, {offset: offset})) {let uint8Array: Uint8Array = new Uint8Array(buf);asrEngine.writeAudio("123456", uint8Array);await this.countDownLatch(1);offset = offset + 1280;}} catch (err) {hilog.error(0x0000, TAG, `Failed to read from file. Code: ${err.code}, message: ${err.message}.`);} finally {if (null != file) {fileIo.closeSync(file);}}}// 麦克风语音转文本private async startRecording() {this.startListeningForRecording();// 录音获取音频let data: ArrayBuffer;hilog.info(0x0000, TAG, 'create capture success');this.mAudioCapturer.init((dataBuffer: ArrayBuffer) => {hilog.info(0x0000, TAG, 'start write');hilog.info(0x0000, TAG, 'ArrayBuffer ' + JSON.stringify(dataBuffer));data = dataBufferlet uint8Array: Uint8Array = new Uint8Array(data);hilog.info(0x0000, TAG, 'ArrayBuffer uint8Array ' + JSON.stringify(uint8Array));// 写入音频流asrEngine.writeAudio("1234567", uint8Array);});};// 计时public async countDownLatch(count: number) {while (count > 0) {await this.sleep(40);count--;}}// 睡眠private sleep(ms: number):Promise<void> {return new Promise(resolve => setTimeout(resolve, ms));}// 设置回调private setListener() {// 创建回调对象let setListener: speechRecognizer.RecognitionListener = {// 开始识别成功回调onStart(sessionId: string, eventMessage: string) {hilog.info(0x0000, TAG, `onStart, sessionId: ${sessionId} eventMessage: ${eventMessage}`);},// 事件回调onEvent(sessionId: string, eventCode: number, eventMessage: string) {hilog.info(0x0000, TAG, `onEvent, sessionId: ${sessionId} eventCode: ${eventCode} eventMessage: ${eventMessage}`);},// 识别结果回调,包括中间结果和最终结果onResult(sessionId: string, result: speechRecognizer.SpeechRecognitionResult) {hilog.info(0x0000, TAG, `onResult, sessionId: ${sessionId} sessionId: ${JSON.stringify(result)}`);},// 识别完成回调onComplete(sessionId: string, eventMessage: string) {hilog.info(0x0000, TAG, `onComplete, sessionId: ${sessionId} eventMessage: ${eventMessage}`);},// 错误回调,错误码通过本方法返回// 返回错误码1002200002,开始识别失败,重复启动startListening方法时触发// 更多错误码请参考错误码参考onError(sessionId: string, errorCode: number, errorMessage: string) {hilog.error(0x0000, TAG, `onError, sessionId: ${sessionId} errorCode: ${errorCode} errorMessage: ${errorMessage}`);},}// 设置回调asrEngine.setListener(setListener);};
}

添加AudioCapturer.ts文件用于获取麦克风音频流。

'use strict';
/** Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.*/import {audio} from '@kit.AudioKit';
import { hilog } from '@kit.PerformanceAnalysisKit';const TAG = 'AudioCapturer';/*** Audio collector tool*/
export default class AudioCapturer {/*** Collector object*/private mAudioCapturer = null;/*** Audio Data Callback Method*/private mDataCallBack: (data: ArrayBuffer) => void = null;/*** Indicates whether recording data can be obtained.*/private mCanWrite: boolean = true;/*** Audio stream information*/private audioStreamInfo = {samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_16000,channels: audio.AudioChannel.CHANNEL_1,sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW}/*** Audio collector information*/private audioCapturerInfo = {source: audio.SourceType.SOURCE_TYPE_MIC,capturerFlags: 0}/*** Audio Collector Option Information*/private audioCapturerOptions = {streamInfo: this.audioStreamInfo,capturerInfo: this.audioCapturerInfo}/***  Initialize* @param audioListener*/public async init(dataCallBack: (data: ArrayBuffer) => void) {if (null != this.mAudioCapturer) {hilog.error(0x0000, TAG, 'AudioCapturerUtil already init');return;}this.mDataCallBack = dataCallBack;this.mAudioCapturer = await audio.createAudioCapturer(this.audioCapturerOptions).catch(error => {hilog.error(0x0000, TAG, `AudioCapturerUtil init createAudioCapturer failed, code is ${error.code}, message is ${error.message}`);});}/*** start recording*/public async start() {hilog.error(0x0000, TAG, `AudioCapturerUtil start`);let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];if (stateGroup.indexOf(this.mAudioCapturer.state) === -1) {hilog.error(0x0000, TAG, `AudioCapturerUtil start failed`);return;}this.mCanWrite = true;await this.mAudioCapturer.start();while (this.mCanWrite) {let bufferSize = await this.mAudioCapturer.getBufferSize();let buffer = await this.mAudioCapturer.read(bufferSize, true);this.mDataCallBack(buffer)}}/*** stop recording*/public async stop() {if (this.mAudioCapturer.state !== audio.AudioState.STATE_RUNNING && this.mAudioCapturer.state !== audio.AudioState.STATE_PAUSED) {hilog.error(0x0000, TAG, `AudioCapturerUtil stop Capturer is not running or paused`);return;}this.mCanWrite = false;await this.mAudioCapturer.stop();if (this.mAudioCapturer.state === audio.AudioState.STATE_STOPPED) {hilog.info(0x0000, TAG, `AudioCapturerUtil Capturer stopped`);} else {hilog.error(0x0000, TAG, `Capturer stop failed`);}}/*** release*/public async release() {if (this.mAudioCapturer.state === audio.AudioState.STATE_RELEASED || this.mAudioCapturer.state === audio.AudioState.STATE_NEW) {hilog.error(0x0000, TAG, `Capturer already released`);return;}await this.mAudioCapturer.release();this.mAudioCapturer = null;if (this.mAudioCapturer.state == audio.AudioState.STATE_RELEASED) {hilog.info(0x0000, TAG, `Capturer released`);} else {hilog.error(0x0000, TAG, `Capturer release failed`);}}
}

EntryAbility.ets文件中添加麦克风权限。

import { abilityAccessCtrl, AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';export default class EntryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');}onDestroy(): void {hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');}onWindowStageCreate(windowStage: window.WindowStage): void {// Main window is created, set main page for this abilityhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');let atManager = abilityAccessCtrl.createAtManager();atManager.requestPermissionsFromUser(this.context, ['ohos.permission.MICROPHONE']).then((data) => {hilog.info(0x0000, 'testTag', 'data:' + JSON.stringify(data));hilog.info(0x0000, 'testTag', 'data permissions:' + data.permissions);hilog.info(0x0000, 'testTag', 'data authResults:' + data.authResults);}).catch((err: BusinessError) => {hilog.error(0x0000, 'testTag', 'errCode: ' + err.code + 'errMessage: ' + err.message);});windowStage.loadContent('pages/Index', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');});}onWindowStageDestroy(): void {// Main window is destroyed, release UI related resourceshilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');}onForeground(): void {// Ability has brought to foregroundhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');}onBackground(): void {// Ability has back to backgroundhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');}
}

相关文章:

【鸿蒙开发】第二十四章 AI - Core Speech Kit(基础语音服务)

目录 1 简介 1.1 场景介绍 1.2 约束与限制 2 文本转语音 2.1 场景介绍 2.2 约束与限制 2.3 开发步骤 2.4 设置播报策略 2.4.1 设置单词播报方式 2.4.2 设置数字播报策略 2.4.3 插入静音停顿 2.4.4 指定汉字发音 2.5 开发实例 3 语音识别 3.1 场景介绍 3.2 约束…...

Java | RESTful 接口规范

关注&#xff1a;CodingTechWork 引言 作为一名程序员&#xff0c;制定清晰、一致且高效的 RESTful 接口规范对于团队的开发效率和项目的长期维护至关重要。本文将详细介绍 RESTful 接口的设计理念、请求方法分类、核心规范&#xff0c;以及正确和错误的示例&#xff0c;帮助团…...

shell脚本控制——处理信号

Linux利用信号与系统中的进程进行通信。你可以通过对脚本进行编程&#xff0c;使其在收到特定信号时执行某些命令&#xff0c;从而控制shell脚本的操作。 1.重温Linux信号 Linux系统和应用程序可以产生超过30个信号。下表列出了在shell脚本编程时会遇到的最常见的Linux系统信…...

OpenGL学习笔记(十二):初级光照:投光物/多光源(平行光、点光源、聚光)

文章目录 平行光点光源聚光多光源 现实世界中&#xff0c;我们有很多种类的光照&#xff0c;每种的表现都不同。将光投射(Cast)到物体的光源叫做投光物(Light Caster)。 平行光/定向光(Directional Light)点光源(Point Light)聚光(Spotlight) 平行光 当一个光源处于很远的地…...

redis底层数据结构——整数集合

文章目录 定义内部实现升级升级的好处提升灵活性节约内存 降级总结 定义 整数集合&#xff08;intset&#xff09;是集合键的底层实现之一&#xff0c;当一个集合只包含整数值元素&#xff0c;并且这个集合的元素数量不多时&#xff0c;Redis就会使用整数集合作为集合键的底层…...

w198基于Springboot的智能家居系统

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…...

【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter2-HTML 中的 JavaScript

二、HTML 中的 JavaScript 将 JavaScript 插入 HTML 的主要方法是使用<script>元素。 <script>元素有下列 8 个属性。 async&#xff1a;可选。表示应该立即开始下载脚本&#xff0c;但不能阻止其他页面动作&#xff0c;比如下载资源或等待其他脚本加载。只对外部…...

【5】阿里面试题整理

[1]. 介绍一下ZooKeeper ZooKeeper是一个开源的分布式协调服务&#xff0c;核心功能是通过树形数据模型&#xff08;ZNode&#xff09;和Watch机制&#xff0c;解决分布式系统的一致性问题。 它使用ZAB协议保障数据一致性&#xff0c;典型场景包括分布式锁、配置管理和服务注…...

系统思考—自我超越

“人们往往认为是个人的能力限制了他们&#xff0c;但事实上&#xff0c;是组织的结构和惯性思维限制了他们的潜力。”—彼得圣吉 最近和一家行业隐形冠军交流&#xff0c;他们已经是领域第一&#xff0c;老板却依然要求&#xff1a;核心团队都要自我超越&#xff0c;攻坚克难…...

大模型-ALIGN 详细介绍

ALIGN模型&#xff08;A Large-scale ImaGe and Noisy-text embedding&#xff09;是一种大规模图像和噪声文本嵌入模型&#xff0c;它通过对比学习的方式将图像和文本嵌入到同一个向量空间中&#xff0c;使得匹配的图像-文本对的嵌入向量接近&#xff0c;不匹配的则远离。这种…...

【C++高并发服务器WebServer】-15:poll、epoll详解及实现

本文目录 一、poll二、epoll2.1 相对poll和select的优点2.2 epoll的api2.3 epoll的demo实现2.5 epoll的工作模式 一、poll poll是对select的一个改进&#xff0c;我们先来看看select的缺点。 我们来看看poll的实现。 struct pollfd {int fd; /* 委托内核检测的文件描述符 */s…...

【算法】动态规划专题⑩ —— 混合背包问题 python

目录 前置知识进入正题总结 前置知识 【算法】动态规划专题⑤ —— 0-1背包问题 滚动数组优化 【算法】动态规划专题⑥ —— 完全背包问题 python 【算法】动态规划专题⑦ —— 多重背包问题 二进制分解优化 python 混合背包结合了三种不同类型的背包问题&#xff1a;0/1背包…...

Java高频面试之SE-20

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; Java的泛型是什么&#xff1f; Java 泛型&#xff08;Generics&#xff09; 是 Java 5 引入的一项重要特性&#xff0c;用于增强代码的类型安…...

springboot 事务管理

在Spring Boot中&#xff0c;事务管理是通过Spring框架的事务管理模块来实现的。Spring提供了声明式事务管理和编程式事务管理两种方式。通常&#xff0c;我们使用声明式事务管理&#xff0c;因为它更简洁且易于维护。 1. 声明式事务管理 声明式事务管理是通过注解来实现的。…...

opentelemetry-collector 配置elasticsearch

一、修改otelcol-config.yaml receivers:otlp:protocols:grpc:endpoint: 0.0.0.0:4317http:endpoint: 0.0.0.0:4318 exporters:debug:verbosity: detailedotlp/jaeger: # Jaeger supports OTLP directlyendpoint: 192.168.31.161:4317tls:insecure: trueotlphttp/prometheus: …...

IDEA关联Tomcat,部署JavaWeb项目

将IDEA与Tomcat关联 创建JavaWeb项目 创建Demo项目 将Tomcat作为依赖引入到Demo中 添加 Web Application 编写前端和后端代码 配置Tomcat server&#xff0c;并运行...

位图与位运算的深度联系:从图像处理到高效数据结构的C++实现与优化

在学习优选算法课程的时候&#xff0c;博主学习位运算了解到位运算的这个概念&#xff0c;之前没有接触过&#xff0c;就查找了相关的资料&#xff0c;丰富一下自身&#xff0c;当作课外知识来了解一下。 位图&#xff08;Bitmap&#xff09;&#xff1a; 在计算机科学中有两种…...

运维_Mac环境单体服务Docker部署实战手册

Docker部署 本小节&#xff0c;讲解如何将前端 后端项目&#xff0c;使用 Docker 容器&#xff0c;部署到 dev 开发环境下的一台 Mac 电脑上。 1 环境准备 需要安装如下环境&#xff1a; Docker&#xff1a;容器MySQL&#xff1a;数据库Redis&#xff1a;缓存Nginx&#x…...

DeepSeek-V3 论文解读:大语言模型领域的创新先锋与性能强者

论文链接&#xff1a;DeepSeek-V3 Technical Report 目录 一、引言二、模型架构&#xff1a;创新驱动性能提升&#xff08;一&#xff09;基本架构&#xff08;Basic Architecture&#xff09;&#xff08;二&#xff09;多令牌预测&#xff08;Multi-Token Prediction&#xf…...

react使用if判断

1、第一种 function Dade(req:any){console.log(req)if(req.data.id 1){return <span>66666</span>}return <span style{{color:"red"}}>8888</span>}2、使用 {win.map((req,index) > ( <> <Dade data{req}/>{req.id 1 ?…...

opencv:基于暗通道先验(DCP)的内窥镜图像去雾

目录 项目大体情况 暗通道先验&#xff08;Dark Channel Prior, DCP&#xff09;原理 项目代码解析 该项目是由我和我导师与舟山某医院合作开发的一个基于暗通道先验&#xff08;Dark Channel Prior&#xff0c;DCP&#xff09;的内窥镜图像去雾方法。具体来说&#xff0c;…...

2025年物联网相关专业毕业论文选题参考,文末联系,选题相关资料提供

一、智能穿戴解决方案研究方向 序号解决方案论文选题论文研究方向1智能腰带健康监测基于SpringBoot和Vue的智能腰带健康监测数据可视化平台开发研究如何利用SpringBoot和Vue技术栈开发一个数据可视化平台&#xff0c;用于展示智能腰带健康监测采集的数据&#xff0c;如心率、血…...

npm无法加载文件 因为此系统禁止运行脚本

安装nodejs后遇到问题&#xff1a; 在项目里【node -v】可以打印出来&#xff0c;【npm -v】打印不出来&#xff0c;显示npm无法加载文件 因为此系统禁止运行脚本。 但是在winr&#xff0c;cmd里【node -v】,【npm -v】都也可打印出来。 解决方法&#xff1a; cmd里可以打印出…...

使用PyCharm创建项目以及如何注释代码

创建好项目后会出现如下图所示的画面&#xff0c;我们可以通过在项目文件夹上点击鼠标右键&#xff0c;选择“New”菜单下的“Python File”来创建一个 Python 文件&#xff0c;在给文件命名时建议使用英文字母和下划线的组合&#xff0c;创建好的 Python 文件会自动打开&#…...

Qt中QFile文件读写操作和QFileInfo文件信息读取方法(详细图文教程)

&#x1f4aa; 图像算法工程师&#xff0c;专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &a…...

CF998A Balloons​ 构造 ​

Balloons 算法&#xff1a;构造 rating : 1000 思路&#xff1a; 分情况讨论&#xff1a; 1. 当只有一个气球包时&#xff0c;肯定不行 2.当有两个气球包时&#xff0c;若两个气球包的气球个数相同则不行 3.其余的情况都是可以的&#xff0c;题目问给格里高利的气球包数…...

python基础入门:3.5实战:词频统计工具

Python词频统计终极指南&#xff1a;字典与排序的完美结合 import re from collections import defaultdictdef word_frequency_analysis(file_path, top_n10):"""完整的词频统计解决方案:param file_path: 文本文件路径:param top_n: 显示前N个高频词:return:…...

面试准备——Java理论高级【笔试,面试的核心重点】

集合框架 Java集合框架是面试中的重中之重&#xff0c;尤其是对List、Set、Map的实现类及其底层原理的考察。 1. List ArrayList&#xff1a; 底层是动态数组&#xff0c;支持随机访问&#xff08;通过索引&#xff09;&#xff0c;时间复杂度为O(1)。插入和删除元素时&#…...

Docker 部署 verdaccio 搭建 npm 私服

一、镜像获取 # 获取 verdaccio 镜像 docker pull verdaccio/verdaccio 二、修改配置文件 cd /wwwroot/opt/docker/verdaccio/conf vim config.yaml config.yaml 配置文件如下&#xff0c;可以根据自己的需要进行修改 # # This is the default configuration file. It all…...

每日一题--数组中只出现一次的两个数字

数组中只出现一次的两个数字 题目描述数据范围提示 示例示例1示例2 题解解题思路位运算方法步骤&#xff1a; 代码实现代码解析时间与空间复杂度按位与操作获取最小位1的原理为什么选择最低有效的 1 位而不是其他位&#xff1f; 题目描述 一个整型数组里除了两个数字只出现一次…...

蓝耘智算平台与DeepSeek R1模型:推动深度学习发展

公主请阅 前言何为DeepSeek R1DeepSeek R1 的特点DeepSeek R1 的应用领域DeepSeek R1 与其他模型的对比 何为蓝耘智算平台使用蓝耘智算平台深度使用DeepSeek R1代码解释&#xff1a;处理示例输入&#xff1a;输出结果&#xff1a; 前言 在深度学习领域&#xff0c;创新迭代日新…...

数据中台是什么?:架构演进、业务整合、方向演进

文章目录 1. 引言2. 数据中台的概念与沿革2.1 概念定义2.2 历史沿革 3. 数据中台的架构组成与关键技术要素解析3.1 架构组成3.2 关键技术要素 4. 数据中台与其他平台的对比详细解析 5. 综合案例&#xff1a;金融行业数据中台落地实践5.1 背景5.2 解决方案5.3 成果与价值 6. 方向…...

告别2023~2024

时间过得真快&#xff0c;距离上次写作2年多了。2023年&#xff5e;2024年的这两年时光里经历太多人生大事&#xff1a; 房贷&#xff0c;提前还贷买车&#xff0c;全款拿下租房搬家媳妇怀孕&#xff0c;独自照顾&#xff0c;……老人离世开盲盒喜提千金&#xff0c;百岁宴&am…...

PMO项目管理规范标准

这份文档是一份关于 PMO 项目管理规范标准的 V3.0 版本。以下是该文档的主要内容&#xff1a; 1. 立项管理 - 立项标准、级别划分和管理&#xff1a;定义了立项管理的标准、级别划分和管理&#xff0c;包括立项的审批流程、产品可行性分析、立项建议书、产品需求文档等。 - 立项…...

通过类加载和初始化的一些题目理解Java类加载过程

通过题目重点理解&#xff1a;Class加载流程和运行时区域 目录 子类和父类static变量父子类加载顺序2class.forName初始化 子类和父类static变量 class Parent {static int a 1;static int b 2;static int c;static {c 3;System.out.println("parent static block&quo…...

【人工智能】解码语言之谜:使用Python构建神经机器翻译系统

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 神经机器翻译(NMT)是近年来机器翻译领域的一项重大突破。它利用深度学习模型,特别是循环神经网络(RNN)和Transformer网络,以端到端的…...

瑞芯微 Rockchip 系列 RK3588 主流深度学习框架模型转成 rknn 模型教程

前言 在瑞芯微 Rockchip 芯片上进行 NPU 推理&#xff0c;需要先将模型文件转换成 rknn 模型文件&#xff0c;才能执行各种推理任务。本文将介绍如何安装各种工具&#xff0c;并最终实现将各种深度学习框架的模型文件转换成 rknn 文件。 本教程不仅适合 RK3588 平台&#xff…...

51单片机俄罗斯方块计分函数

/************************************************************************************************************** * 名称&#xff1a;scoring * 功能&#xff1a;计分 * 参数&#xff1a;NULL * 返回&#xff1a;NULL * 备注&#xff1a;采用非阻塞延时 ****************…...

C++线程池

使用线程情况比较频繁的地方&#xff0c;由于线程的创建及销毁都会产生对资源的占用及性能的损耗。为了优化性能&#xff0c;提升效率&#xff0c;在这种场景中&#xff0c;就应该使用线程池来处理任务。 线程池创建的关键点&#xff1a; 装载线程的容器&#xff0c;在C中使用…...

Golang GORM系列:定义GORM模型及关系指南

使用GORM进行数据库管理的核心是定义模型的技能。模型是程序的面向对象结构和数据库的关系世界之间的纽带。本文深入研究了在GORM中创建成功模型的艺术&#xff0c;研究了如何设计结构化的Go结构&#xff0c;用标记注释字段&#xff0c;以及开发跨模型的链接&#xff0c;以便最…...

ssm校园二手交易平台小程序

博主介绍&#xff1a;✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…...

【虚幻引擎UE】AOI算法介绍与实现案例

【虚幻引擎UE】AOI算法介绍与实现 一、AOI算法介绍AOI算法的典型应用场景二、AOI相关算法1. 边界框法(Bounding Box Method)2. 动态AOI算法3. 布尔运算(Boolean Operations)4. 四叉树(Quadtree)5. R树(R-Tree)6. 圆形AOI算法7. 网格分割(Grid Partitioning)8. 多边形…...

JavaScript 基础语法:变量、数据类型、运算符、条件语句、循环

JavaScript 是一种动态类型的脚本语言&#xff0c;广泛用于前端开发。以下是 JavaScript 基础语法的核心内容&#xff0c;包括变量、数据类型、运算符、条件语句和循环。 --- ### 1. 变量 变量用于存储数据。JavaScript 中有三种声明变量的方式&#xff1a; - **var**&…...

ASP.NET Core 如何使用 C# 从端点发出 GET 请求

使用 C#&#xff0c;从 REST API 端点获取 JSON&#xff1b;如何从 REST API 接收 JSON 数据。 本文需要 ASP .NET Core&#xff0c;并兼容 .NET Core 3.1、.NET 6和.NET 8。 要将数据发布到端点&#xff0c;请参阅本文。 使用 . 从端点发布 GET 数据非常容易HttpClient&…...

Docker 部署 MinIO | 国内阿里镜像

一、导读 Minio 是个基于 Golang 编写的开源对象存储套件&#xff0c;基于Apache License v2.0开源协议&#xff0c;虽然轻量&#xff0c;却拥有着不错的性能。它兼容亚马逊S3云存储服务接口。可以很简单的和其他应用结合使用&#xff0c;例如 NodeJS、Redis、MySQL等。 二、…...

量化交易数据获取:xtquant库的高效应用

量化交易数据获取&#xff1a;xtquant库的高效应用 在量化交易领域&#xff0c;历史行情数据的重要性不言而喻。它不仅为策略回测提供基础&#xff0c;也是实时交易决策的重要参考。本文将介绍如何使用xtquant库来高效获取和处理历史行情数据。 技术背景与应用场景 对于量化…...

Mysql中存储引擎各种介绍以及应用场景、优缺点

概述 MySQL 提供了多种存储引擎&#xff0c;每种引擎有不同的特点和适用场景。以下是几种常见的 MySQL 存储引擎的详细介绍&#xff0c;包括它们的底层工作原理、优缺点&#xff0c;以及为什么 MySQL 默认选择某种引擎。 1. InnoDB 底层工作原理&#xff1a; 事务支持&#…...

面试题整理:Java虚拟机 JVM 内存区域、垃圾回收、类加载器

文章目录 JVM虚拟机内存区域1. ⭐JVM的内存区域有哪些&#xff1f;每个区域的作用是什么&#xff1f;2. 堆和栈的区别是什么&#xff1f;3. 堆内存是如何划分的&#xff1f;4. 永久代和元空间是什么关系&#xff1f;5. 对JVM常量池的理解&#xff1f;6. ⭐Java 对象的创建过程&…...

ASP.NET Core 使用 WebClient 从 URL 下载

本文使用 ASP .NET Core 3.1&#xff0c;但它在.NET 5、 .NET 6和.NET 8上也同样适用。如果使用较旧的.NET Framework&#xff0c;请参阅本文&#xff0c;不过&#xff0c;变化不大。 如果想要从 URL 下载任何数据类型&#xff0c;请参阅本文&#xff1a;HttpClient 使用WebC…...

第六届MathorCup高校数学建模挑战赛-A题:淡水养殖池塘水华发生及池水自净化研究

目录 摘要 1 问题的重述 2 问题的分析 2.1 问题一的分析 2.2 问题二的分析 2.3 问题三的分析 2.4 问题四的分析 2.5 问题五的分析 3. 问题的假设 4. 符号说明 5. 模型的建立与求解 5.1 问题一的建模与求解 5.1.1 分析对象与指标的选取 5.1.2 折线图分析 5.1.3 相关性分析 5.1.4…...