正文
*图片来源
:
Android Blog: https://android-developers.googleblog.com/2024/05/android-support-for-kotlin-multiplatform-to-share-business-logic-across-mobile-web-server-desktop.html
尽管 Mediapipe 也支持多个平台,但我们这次主要聚焦在 Android 和 iOS。一方面更贴近现实,各行各业使用 KMP 的公司的用例更多在移动端上;另外一方面也更方便对标其他移动端开发技术栈。
使用 IDEA 或 Android Studio 创建一个 KMP 的基础工程,你可以借助 KMP Wizard 或者第三方 KMP App 的模版。如果你没有 KMP 的相关经验,可以看到它其实就是一个非常类似 Android 工程的结构,只不过这一次我们把 iOS 的壳工程也放到根目录,并且在 app 模块的
build.gradle.kts
内同时配置了 iOS 的相关依赖。
我们在
commonMain
中,根据 Mediapipe LLM Task SDK 的特征抽象一个简单的接口,使用 Kotlin 编写,用以满足 Android 和 iOS 两端的需要。该接口取代了原有仓库里的
InferenceModel.kt
类。
interface LLMOperator {
suspend fun initModel(): String?
fun sizeInTokens(text: String): Int
suspend fun generateResponse(inputText: String): String
suspend fun generateResponseAsync(inputText: String): FlowBoolean>>
}
在 Android 上面,因为 LLM Task SDK 原先就是 Kotlin 实现的,所以除了初始化加载模型文件,其余的部分基本就是代理原有的 SDK 功能。
class LLMInferenceAndroidImpl(private val ctx: Context): LLMOperator {
private lateinit var llmInference: LlmInference
private val initialized = AtomicBoolean(false)
private val partialResultsFlow = MutableSharedFlowBoolean>>(...)
override suspend fun initModel(): String? {
if (initialized.get()) {
return null
}
return try {
val modelPath = ...
if (File(modelPath).exists().not()) {
return "Model not found at path: $modelPath"
}
loadModel(modelPath)
initialized.set(true)
null
} catch (e: Exception) {
e.message
}
}
private fun loadModel(modelPath: String) {
val options = LlmInference.LlmInferenceOptions.builder()
.setModelPath(modelPath)
.setMaxTokens(1024)
.setResultListener { partialResult, done ->
partialResultsFlow.tryEmit(partialResult to done)
}
.build()
llmInference = LlmInference.createFromOptions(ctx, options)
}
override fun sizeInTokens(text: String): Int = llmInference.sizeInTokens(text)
override suspend fun generateResponse(inputText: String