1、介绍
总览
Cloud DB(云数据库)是一款端云协同的数据库产品,提供端云数据的协同管理、统一的数据模型和丰富的数据管理API接口等能力。在保证数据的可用性、可靠性、一致性,以及安全等特性基础上,能够实现数据在客户端和云端之间的无缝同步。
ML Kit为(机器学习服务)开发者提供简单易用、服务多样、技术领先的机器学习能力,助力开发者更快更好地开发各类AI应用。
您将建立什么
在本次Codelab中,您将建立一个示例项目并集成ML Kit和Cloud DB。在该项目中,您可以:
1、使用键盘或图像分类进行图像搜索
2、列出Cloud DB中的图像
3、检测图像描述的语言
4、翻译图像描述
5、声化图像描述
您需要什么
在本codelab中,你需要学习:
1、如何在AppGallery Connect中创建项目和应用程序
2、如何集成ML Kit和Cloud DB
3、如何使用ML Kit和Cloud DB
2、您需要什么
硬件需求
一台笔记本或台式电脑。
华为手机:EMUI 8.0版本或以上,运行HMS Core (APK) 5.0.1.301及以上版本;非华为手机:Android 7.0或以上,运行HMS Core (APK) 5.0.1.301或以上版本。
手机用于运行和调试demo
软件需求
JDK版本:1.8或以上
Android Studio版本:3.X或以上
minSdkVersion:24或以上
targetSdkVersion:29
compileSdkVersion:29
Gradle版本:4.6或以上
必备知识
安卓应用开发基础知识
3、集成前准备
集成前,需要完成以下准备工作:
说明:
在进行准备前,请先注册开发者帐号。
在AppGallery Connect中创建项目和应用。
创建Android Studio项目。
生成签名证书。
生成签名证书指纹。
在AppGallery Connect中将签名指纹添加到应用中。
添加必要配置。
配置项目签名。
同步项目。
详情请参见HUAWEI HMS Core集成准备。
4、集成HMS Core SDK
添加您应用的AppGallery Connect配置文件
登录AppGallery Connect,点击“我的项目”,在项目列表中找到并点击您的项目。
在“项目设置”页面选择“常规”页签。
在“项目”区域下点击“数据处理位置”后的“启用”。
点击“应用”区域的“agconnect-services.json”下载配置文件。
将配置文件"agconnect-services.json"复制到应用级根目录下。
添加编译依赖
打开应用级的“build.gradle”文件。
在dependencies代码段中添加如下编译依赖。
dependencies { // Import Cloud DB. implementation 'com.huawei.agconnect:agconnect-cloud-database:{version}' // Import Image Classification implementation 'com.huawei.hms:ml-computer-vision-classification:{version}' // Import Image Classification Model Implementation 'com.huawei.hms:ml-computer-vision-image-classification-model:{version}' // Import Real-Time Translation implementation 'com.huawei.hms:ml-computer-translate:{version}' // Import Real-Time Language Detection implementation 'com.huawei.hms:ml-computer-language-detection:{version}' // Import Text To Speech implementation 'com.huawei.hms:ml-computer-voice-tts:{version}' }
具体说明如下:
a.将{version}替换为Cloud DB的新版本号,例如com.huawei.agconnect:agconnect-cloud-database:1.5.4.300。有关新版本号的详细信息,请参见文档。
b.将{version}替换为ML Kit的新版本号,例如com.huawei.agconnect:agconnect-function-ktx 1.7.1.300。有关新版本号的详细信息,请参见文档。
在build.gradle文件中,设置Java源代码的兼容性模式为JDK1.8。
compileOptions { sourceCompatibility = 1.8 targetCompatibility = 1.8 }
在应用级build.gradle文件中设置minSdkVersion。
android { ... defaultConfig { ... minSdkVersion 26 ... } ... }
检查是否已添加AppGallery Connect插件。如没有,在应用级build.gradle文件中添加该插件。
apply plugin: 'com.huawei.agconnect'
配置混淆脚本
编译APK前需要配置混淆脚本,避免混淆HMS Core SDK。如果出现混淆,HMS Core SDK可能无法正常工作。
Android Studio开发环境里的混淆脚本是“proguard-rules.pro”。
加入排除HMS SDK的混淆配置。
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.huawei.hianalytics.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
5、设计UI
6、在AppGallery Connect中初始化云数据库
步骤一:创建云数据库的存储区
1)登录AppGallery Connect,单击我的项目。
2)在项目列表中选择一个项目,单击需要添加Cloud DB区域的应用。
3)在左侧导航栏中,选择“Serverless > 云数据库”。
4)点击云数据库区域选项卡。
5)点击“新增”,进入云数据库区域创建页面。
步骤二:在AGC中创建云数据库对象类型
1)登录AppGallery Connect,单击我的项目。
2)在项目列表中选择一个项目,单击需要添加Cloud DB区域的应用。
3)在左侧导航栏中,选择“Serverless > 云数据库”。
4)根据需求执行以下操作:
a.创建对象类型:点击“新增”
b.编辑现有对象类型:点击“修改”
7、初始化云数据库
步骤一:初始化云数据库
private lateinit var mCloudDB: AGConnectCloudDB
private var handler: CompletableDeferred<Result<Unit>>? = null
private var cloudDBZone: CloudDBZone? = null
override suspend fun initialize(): Result<Unit> {
handler = CompletableDeferred()
AGConnectCloudDB.initialize(context)
initializeCloudDB()
initializeZone()
handler?.let { return it.await() }
?: run { return Result.Error("An error occurred") }
}
private fun initializeCloudDB() {
val instance = AGConnectInstance.buildInstance(
AGConnectOptionsBuilder().setRoutePolicy(
AGCRoutePolicy.GERMANY
).build(context)
)
mCloudDB = AGConnectCloudDB.getInstance(
instance,
AGConnectAuth.getInstance()
) mCloudDB.createObjectType(ObjectTypeInfoHelper.getObjectTypeInfo())
}
private fun initializeZone() {
val mConfig = CloudDBZoneConfig(
"ImageDbZone",
CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE, CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC
)
mConfig.persistenceEnabled = true
val task = mCloudDB.openCloudDBZone2(mConfig, true)
task.addOnSuccessListener {
cloudDBZone = it
handler?.complete(Result.Success(Unit))
}.addOnFailureListener {
handler?.complete(Result.Error(it.message ?: "An error occurred."))
}
}
步骤二:将“query”作为搜索入参。对于接收到的“query”。根据图像对象对应的“key”字段在Cloud DB中完成过滤,根据过滤结果列出云数据库中的图像对象。
override suspend fun searchImage(query: String): List<Image> {
val result = CompletableDeferred<List<Image>>()
cloudDBZone?.let { dbZone ->
dbZone.executeQuery(
CloudDBZoneQuery.where(Image::class.java)
.equalTo("key", query),
CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_DEFAULT
).addOnCompleteListener{
if(it.isSuccessful) {
val cursor = it.result.snapshotObjects
val images = mutableListOf<Image>()
while(cursor.hasNext()) {
images.add(cursor.next())
}
result.complete(images)
}else {
throw it.exception
}
}
}?: run {
throw CloudDbNotInitializedException()
}
return result.await()}
8、集成机器学习服务
步骤一:查看权限。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
步骤二:ML Kit方法返回Task。创建Task.await()扩展函数,用于在协程和Task API之间转换。Task.await()等待任务完成,而不阻塞线程,并返回未包装的结果(Task<T>中的T)。
suspend fun <T> Task<T>.await(): T = suspendCoroutine { continuation ->
addOnCompleteListener { task ->
if (task.isSuccessful) {
continuation.resume(task.result)
} else {
continuation.resumeWithException(
task.exception ?: Exception("Unknown task exception")
)
}
}
}
步骤三:图像分类
/**
* Step 1: Create an image classification analyzer.
* Use customized parameter settings or default parameter settings
* for on-device recognition.
*
* Customized ->
* var setting = MLLocalClassificationAnalyzerSetting
* .Factory()
* .setMinAcceptablePossibility(0.8f)
* .create()
* var analyzer = MLAnalyzerFactory
* .getInstance()
* .getLocalImageClassificationAnalyzer(setting)
*
* Default -> var analyzer = MLAnalyzerFactory
* .getInstance()
* .localImageClassificationAnalyzer
*
* Step 2: Create an MLFrame object using android.graphics.Bitmap.
* JPG, JPEG, PNG, and BMP images are supported.
*
* Step 3: Call the asyncAnalyseFrame method to classify images.
*
* Step 4: After the recognition is complete, stop the analyzer to
* release recognition resources.
*/
override suspend fun classifyImage(bitmap: Bitmap): List<MLImageClassification> {
val analyzer = MLAnalyzerFactory
.getInstance()
.localImageClassificationAnalyzer //Step 1
val frame = MLFrame.fromBitmap(bitmap) //Step 2
val task = analyzer.asyncAnalyseFrame(frame) //Step 3
val classificationResult = task.await()
analyzer.stop() //Step 4
return classificationResult
}
步骤四:语种检测
/**
* Step 1: Create a language detector.
* Use customized parameter settings or default parameter settings
* to create a language detector.
*
* Customized -> val setting = MLRemoteLangDetectorSetting
* .Factory()
* .setTrustedThreshold(0.01f)
* .create()
* val mlRemoteLangDetector = MLLangDetectorFactory
* .getInstance()
* .getRemoteLangDetector(setting)
*
* Default -> val mlRemoteLangDetector = MLLangDetectorFactory
* .getInstance()
* .remoteLangDetector
*
* Step 2: Implement language detection.
*
* Step 3: Release resources after the detection is complete.
*/
override suspend fun detectLanguage(text: String): String {
val mlRemoteLangDetector = MLLangDetectorFactory //Step 1
.getInstance()
.remoteLangDetector
val firstBestDetectTask = mlRemoteLangDetector //Step 2
.firstBestDetect(text)
val detectResult = firstBestDetectTask.await()
mlRemoteLangDetector.stop() //Step 3
return detectResult
}
步骤五:文本翻译
/**
* Step 1: Create a real-time text translator.
* Language Code -> The BCP-47 standard is used for Traditional Chinese,
* and the ISO 639-1 standard is used for other languages.
*
* Step 2: Implement real-time translation.
*
* Step 3: Release resources after the translation is complete.
*/
override suspend fun translateText(
text: String,
sourceLanguage:String,
targetLanguage: String
): String {
val setting = MLRemoteTranslateSetting //Step 1
.Factory()
.setSourceLangCode(sourceLanguage)
.setTargetLangCode(targetLanguage)
.create()
val mlRemoteTranslator = MLTranslatorFactory
.getInstance()
.getRemoteTranslator(setting)
val translatorTask = mlRemoteTranslator //Step 2
.asyncTranslate(text)
val translationResult = translatorTask.await()
mlRemoteTranslator.stop() //Step 3
return translationResult
}
步骤六:语音合成
private lateinit var mlTtsEngine: MLTtsEngine
private lateinit var mlConfigs: MLTtsConfig
// Step 1: Create a TTS engine.
override fun createInstance(){
// Use customized parameter settings to create a TTS engine.
mlConfigs = MLTtsConfig()
// Set the text converted from speech to English.
.setLanguage(MLTtsConstants.TTS_EN_US)
// Set the English timbre.
.setPerson(MLTtsConstants.TTS_SPEAKER_FEMALE_EN)
// Set the speech speed.
// The range is (0,5.0]. 1.0 indicates a normal speed.
.setSpeed(1.0f)
// Set the volume.
// The range is (0,2). 1.0 indicates a normal volume.
.setVolume(1.0f)
mlTtsEngine = MLTtsEngine(mlConfigs)
mlTtsEngine.setTtsCallback(callback)
}
// Step 3: Control the playback
override fun startSpeaking(text: String) {
mlTtsEngine.speak(text,MLTtsEngine.QUEUE_APPEND)
}
// Step 3: Control the playback
override fun resumeSpeaking() {
mlTtsEngine.resume()
}
// Step 3: Control the playback
override fun pauseSpeaking() {
mlTtsEngine.pause()
}
// Step 4: Stop the ongoing TTS tasks and clear all TTS tasks in the queue.
override fun stopSpeaking() {
mlTtsEngine.stop()
}
// Step 5: Release resources after TTS ends.
override fun shutDownTextToSpeech() {
mlTtsEngine.shutdown()
}
// Step 2: Create a TTS callback function to process the TTS result.
//Pass the TTS callback to the TTS engine created in Step 1 to perform TTS.
private var callback: MLTtsCallback = object : MLTtsCallback {
override fun onEvent(taskId: String, eventName: Int, bundle: Bundle?) {
when(eventName){
MLTtsConstants.EVENT_PLAY_START -> {/* Handle Event */}
MLTtsConstants.EVENT_PLAY_RESUME -> {/* Handle Event */}
MLTtsConstants.EVENT_PLAY_PAUSE -> {/* Handle Event */}
MLTtsConstants.EVENT_PLAY_STOP -> {/* Handle Event */}
MLTtsConstants.EVENT_SYNTHESIS_START -> {/* Handle Event */}
MLTtsConstants.EVENT_SYNTHESIS_END -> {/* Handle Event */}
MLTtsConstants.EVENT_SYNTHESIS_COMPLETE -> {{/* Handle Event */}}
}
}
override fun onError(taskId: String, err: MLTtsError) {
//Processing logic for TTS failure.
}
override fun onWarn(taskId: String, warn: MLTtsWarn) {
//Alarm handling without affecting service logic.
}
//Return the mapping between the currently played segment and text.
//start: start position of the audio segment in the input text;
//end (excluded): end position of the audio segment in the input text
override fun onRangeStart(taskId: String, start: Int, end: Int) {
//Process the mapping between the currently played segment and text.
}
//taskId: ID of an audio synthesis task corresponding to the audio.
//audioFragment: audio data.
//offset: offset of the audio segment to be transmitted in the queue.
//One audio synthesis task corresponds to an audio synthesis queue.
//range: text area where the audio segment to be transmitted is located;
//range.first (included): start position;
//range.second (excluded): end position.
override fun onAudioAvailable(
taskId: String?,
audioFragment: MLTtsAudioFragment?,
offset: Int,
range: android.util.Pair<Int, Int>?,
bundle: Bundle?
) {
//Audio stream callback API,
// which is used to return the synthesized audio data to the app.
}
}
9、恭喜您
祝贺您,您已经成功完成本codelab并学到了:
如何集成云数据库。
如何使用ML Kit(图像分类、语种检测、文本翻译、语音合成)。