mirror of https://github.com/alibaba/MNN.git
Releae Version 0.7.1
+ Click here to [download](https://meta.alicdn.com/data/mnn/mnn_chat_0_7_1.apk) + add new models: + [MiniCPM-V-4](https://huggingface.co/openbmb/MiniCPM-V-4): GPT-4V Level MLLM for Single Image, Multi Image and Video on Your Phone + [WebSailor-3B](https://huggingface.co/Alibaba-NLP/WebSailor-3B): a complete post-training methodology designed to teach LLM agents sophisticated reasoning for complex web navigation and information-seeking tasks. + [Lingshu-7B](https://huggingface.co/lingshu-medical-mllm/Lingshu-7B):Multimodal Large Language Models for Medical Domain + bugfix: + Crash when choose images.
This commit is contained in:
parent
a73434ba29
commit
ef2e617b90
|
@ -376,3 +376,4 @@ datasets/*
|
|||
|
||||
# qnn 3rdParty
|
||||
source/backend/qnn/3rdParty/include
|
||||
apps/Android/MnnLlmChat/release_outputs
|
||||
|
|
|
@ -61,6 +61,15 @@ This is our full multimodal language model (LLM) Android app
|
|||
```
|
||||
|
||||
# Releases
|
||||
## Version 0.7.1
|
||||
+ Click here to [download](https://meta.alicdn.com/data/mnn/mnn_chat_0_7_1.apk)
|
||||
+ add new models:
|
||||
+ [MiniCPM-V-4](https://huggingface.co/openbmb/MiniCPM-V-4): GPT-4V Level MLLM for Single Image, Multi Image and Video on Your Phone
|
||||
+ [WebSailor-3B](https://huggingface.co/Alibaba-NLP/WebSailor-3B): a complete post-training methodology designed to teach LLM agents sophisticated reasoning for complex web navigation and information-seeking tasks.
|
||||
+ [Lingshu-7B](https://huggingface.co/lingshu-medical-mllm/Lingshu-7B):Multimodal Large Language Models for Medical Domain
|
||||
+ bugfix:
|
||||
+ Crash when choose images.
|
||||
|
||||
## Version 0.7.0
|
||||
+ Click here to [download](https://meta.alicdn.com/data/mnn/mnn_chat_0_7_0.apk)
|
||||
+ add new models: gpt-oss-20b
|
||||
|
|
|
@ -54,6 +54,15 @@
|
|||
|
||||
# Releases
|
||||
|
||||
## 版本 0.7.1
|
||||
+ [点击此处下载](https://meta.alicdn.com/data/mnn/mnn_chat_0_7_1.apk)
|
||||
+ 新增模型:
|
||||
+ [MiniCPM-V-4](https://huggingface.co/openbmb/MiniCPM-V-4):可在手机上运行的、达到 GPT-4V 水准的多模态大语言模型,支持单图、多图和视频理解
|
||||
+ [WebSailor-3B](https://huggingface.co/Alibaba-NLP/WebSailor-3B):一种完整的后训练方法论,旨在教会大语言模型代理在复杂网页导航和信息检索任务中进行高级推理
|
||||
+ [Lingshu-7B](https://huggingface.co/lingshu-medical-mllm/Lingshu-7B):面向医疗领域的多模态大语言模型
|
||||
+ 问题修复:
|
||||
+ 选择图片时崩溃的问题
|
||||
|
||||
## Version 0.7.0
|
||||
+ Click here to [download](https://meta.alicdn.com/data/mnn/mnn_chat_0_7_0.apk)
|
||||
+ 增加新模型: gpt-oss-20b
|
||||
|
|
|
@ -59,8 +59,8 @@ android {
|
|||
applicationId "com.alibaba.mnnllm.android"
|
||||
minSdk 26
|
||||
targetSdk 35
|
||||
versionCode 700
|
||||
versionName "0.7.0"
|
||||
versionCode 701
|
||||
versionName "0.7.1"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "4",
|
||||
"version": "5",
|
||||
"tagTranslations": {
|
||||
"Vision": "图像理解",
|
||||
"Video": "视频理解",
|
||||
|
@ -92,23 +92,6 @@
|
|||
"vendor": "MiniCPM",
|
||||
"file_size": 2834668967
|
||||
},
|
||||
{
|
||||
"modelName": "gemma-3-270m-it-MNN",
|
||||
"tags": [
|
||||
],
|
||||
"categories": [
|
||||
"recommended",
|
||||
"qwen"
|
||||
],
|
||||
"sources": {
|
||||
"HuggingFace": "taobao-mnn/gemma-3-270m-it-MNN",
|
||||
"ModelScope": "MNN/gemma-3-270m-it-MNN",
|
||||
"Modelers": "MNN/gemma-3-270m-it-MNN"
|
||||
},
|
||||
"size_gb": 0.27,
|
||||
"vendor": "Gemma",
|
||||
"file_size": 308727585
|
||||
},
|
||||
{
|
||||
"modelName": "MiniCPM4-0.5B-MNN",
|
||||
"tags": [
|
||||
|
@ -348,8 +331,7 @@
|
|||
],
|
||||
"sources": {
|
||||
"HuggingFace": "taobao-mnn/ERNIE-4.5-0.3B-PT-MNN",
|
||||
"ModelScope": "MNN/ERNIE-4.5-0.3B-PT-MNN",
|
||||
"Modelers": "MNN/ERNIE-4.5-0.3B-PT-MNN"
|
||||
"ModelScope": "MNN/ERNIE-4.5-0.3B-PT-MNN"
|
||||
},
|
||||
"size_gb": 0.3,
|
||||
"vendor": "ERNIE",
|
||||
|
|
|
@ -423,14 +423,7 @@ class ChatActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
this.chatInputModule!!.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
|
||||
|
||||
private fun handleNewSession() {
|
||||
if (!isGenerating) {
|
||||
|
@ -457,6 +450,20 @@ class ChatActivity : AppCompatActivity() {
|
|||
super.onActivityResult(requestCode, resultCode, data)
|
||||
this.chatInputModule!!.handleResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
// Forward permission results to the attachment picker module
|
||||
this.chatInputModule?.let { inputModule ->
|
||||
if (inputModule is ChatInputComponent) {
|
||||
inputModule.attachmentPickerModule?.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleSendMessage(userData: ChatDataItem): HashMap<String, Any> {
|
||||
return chatPresenter.sendMessage(userData)
|
||||
|
|
|
@ -2,15 +2,19 @@
|
|||
// Copyright (c) 2024 Alibaba Group Holding Limited All rights reserved.
|
||||
package com.alibaba.mnnllm.android.chat.input
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import com.alibaba.mnnllm.android.R
|
||||
import com.alibaba.mnnllm.android.chat.ChatActivity
|
||||
|
@ -85,11 +89,11 @@ class AttachmentPickerModule(private val activity: ChatActivity) {
|
|||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
try {
|
||||
activity.startActivityForResult(
|
||||
Intent.createChooser(intent, "Select a WAV file"),
|
||||
Intent.createChooser(intent, activity.getString(R.string.select_wav_file)),
|
||||
REQUEST_CODE_SELECT_WAV
|
||||
)
|
||||
} catch (ex: ActivityNotFoundException) {
|
||||
Toast.makeText(this.activity, "Please install a File Manager.", Toast.LENGTH_SHORT)
|
||||
Toast.makeText(this.activity, R.string.file_manager_required, Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
@ -106,13 +110,33 @@ class AttachmentPickerModule(private val activity: ChatActivity) {
|
|||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.setType("image/*")
|
||||
activity.startActivityForResult(
|
||||
Intent.createChooser(intent, "Select Picture"),
|
||||
Intent.createChooser(intent, activity.getString(R.string.select_picture)),
|
||||
REQUEST_CODE_SELECT_IMAGE,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
private fun takePhoto() {
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
// Permission is not granted, request it
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)) {
|
||||
// Show rationale to user
|
||||
Toast.makeText(activity, R.string.camera_permission_rationale, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
arrayOf(Manifest.permission.CAMERA),
|
||||
REQUEST_CODE_CAMERA_PERMISSION
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Permission is granted, proceed with camera
|
||||
startCameraIntent()
|
||||
}
|
||||
|
||||
private fun startCameraIntent() {
|
||||
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
|
||||
photoFile = File(
|
||||
FileUtils.generateDestPhotoFilePath(
|
||||
|
@ -127,7 +151,15 @@ class AttachmentPickerModule(private val activity: ChatActivity) {
|
|||
photoFile!!
|
||||
)
|
||||
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileProviderUri)
|
||||
activity.startActivityForResult(cameraIntent, REQUEST_CODE_CAPTURE_IMAGE)
|
||||
try {
|
||||
activity.startActivityForResult(cameraIntent, REQUEST_CODE_CAPTURE_IMAGE)
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "Camera permission denied", e)
|
||||
Toast.makeText(activity, R.string.camera_permission_denied, Toast.LENGTH_SHORT).show()
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Log.e(TAG, "No camera app found", e)
|
||||
Toast.makeText(activity, R.string.no_camera_app_found, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun setOnImagePickCallback(callback: ImagePickCallback?) {
|
||||
|
@ -135,14 +167,14 @@ class AttachmentPickerModule(private val activity: ChatActivity) {
|
|||
}
|
||||
|
||||
fun canHandleResult(requestCode: Int): Boolean {
|
||||
return requestCode >= REQUEST_CODE_SELECT_WAV && requestCode <= REQUEST_CODE_CAPTURE_IMAGE
|
||||
return requestCode >= REQUEST_CODE_SELECT_WAV && requestCode <= REQUEST_CODE_CAPTURE_IMAGE ||
|
||||
requestCode == REQUEST_CODE_CAMERA_PERMISSION
|
||||
}
|
||||
|
||||
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_CODE_CAPTURE_IMAGE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (imageUri != null) {
|
||||
showImagePreview()
|
||||
val imagePath = imageUri?.path
|
||||
Log.d("ImagePath", "Image saved to: $imagePath")
|
||||
showImagePreview()
|
||||
|
@ -181,12 +213,24 @@ class AttachmentPickerModule(private val activity: ChatActivity) {
|
|||
showAudioPreview(Uri.fromFile(destFile))
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "get audio file failed", e)
|
||||
Toast.makeText(this.activity, "get audio file failed", Toast.LENGTH_SHORT)
|
||||
Toast.makeText(this.activity, R.string.audio_file_failed, Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||
if (requestCode == REQUEST_CODE_CAMERA_PERMISSION) {
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// Camera permission granted, proceed with camera
|
||||
startCameraIntent()
|
||||
} else {
|
||||
// Camera permission denied
|
||||
Toast.makeText(activity, R.string.camera_permission_denied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAudioPreview(audioUri: Uri) {
|
||||
attachmentPreview.setImageResource(R.drawable.ic_audio_attachment)
|
||||
|
@ -256,6 +300,7 @@ class AttachmentPickerModule(private val activity: ChatActivity) {
|
|||
companion object {
|
||||
const val TAG: String = "ImagePickerModule"
|
||||
var REQUEST_CODE_CAPTURE_IMAGE: Int = 100
|
||||
const val REQUEST_CODE_CAMERA_PERMISSION: Int = 101
|
||||
|
||||
var REQUEST_CODE_SELECT_IMAGE: Int = 99
|
||||
var REQUEST_CODE_SELECT_WAV: Int = 98
|
||||
|
|
|
@ -42,7 +42,7 @@ class ChatInputComponent(
|
|||
private lateinit var editUserMessage: EditText
|
||||
private var buttonSend: ImageView = binding.btnSend
|
||||
private lateinit var imageMore: ImageView
|
||||
private var attachmentPickerModule: AttachmentPickerModule? = null
|
||||
var attachmentPickerModule: AttachmentPickerModule? = null
|
||||
private lateinit var voiceRecordingModule: VoiceRecordingModule
|
||||
private var currentUserMessage: ChatDataItem? = null
|
||||
private var buttonSwitchVoice: View? = null
|
||||
|
@ -335,6 +335,9 @@ class ChatInputComponent(
|
|||
} else {
|
||||
voiceRecordingModule.handlePermissionDenied()
|
||||
}
|
||||
} else if (attachmentPickerModule != null &&
|
||||
requestCode == AttachmentPickerModule.REQUEST_CODE_CAMERA_PERMISSION) {
|
||||
attachmentPickerModule!!.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</selector>
|
|
@ -54,6 +54,13 @@
|
|||
<string name="diffusion_generate_progress">图片生成进度: %1$s%%</string>
|
||||
<string name="no_history">没有历史记录,请在模型列表页面选择模型聊天</string>
|
||||
<string name="recording_permission_denied">请允许录音权限</string>
|
||||
<string name="camera_permission_denied">需要相机权限才能拍照</string>
|
||||
<string name="camera_permission_rationale">需要相机权限来为聊天拍照</string>
|
||||
<string name="no_camera_app_found">此设备上没有找到相机应用</string>
|
||||
<string name="file_manager_required">请安装文件管理器</string>
|
||||
<string name="audio_file_failed">获取音频文件失败</string>
|
||||
<string name="select_picture">选择图片</string>
|
||||
<string name="select_wav_file">选择 WAV 文件</string>
|
||||
<string name="release_to_send">松开发送,上滑取消</string>
|
||||
<string name="release_to_cancel">松开取消</string>
|
||||
<string name="r1_thinking_message">思考中…</string>
|
||||
|
|
|
@ -55,6 +55,13 @@
|
|||
<string name="diffusion_generate_progress">Image Generate progress: %1$s%%</string>
|
||||
<string name="no_history">No history, please select model in the model list and chat</string>
|
||||
<string name="recording_permission_denied">Please allow permission to record audio</string>
|
||||
<string name="camera_permission_denied">Camera permission is required to take photos</string>
|
||||
<string name="camera_permission_rationale">Camera access is needed to take photos for your chat</string>
|
||||
<string name="no_camera_app_found">No camera app found on this device</string>
|
||||
<string name="file_manager_required">Please install a File Manager</string>
|
||||
<string name="audio_file_failed">Failed to get audio file</string>
|
||||
<string name="select_picture">Select Picture</string>
|
||||
<string name="select_wav_file">Select a WAV file</string>
|
||||
<string name="release_to_send">Release to Send, Slide up to cancel</string>
|
||||
<string name="release_to_cancel">Release to cancel</string>
|
||||
<string name="scroll_to_bottom">Scroll to bottom</string>
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Model Test Script for MnnLlmChat
|
||||
# This script pushes model files and test binaries to the phone and runs a test
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/push_model_test.sh # Normal verbose output
|
||||
# VERBOSE=false ./scripts/push_model_test.sh # Quiet mode, less output
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
PROJECT_NAME="MnnLlmChat"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ROOT_PROJECT_DIR="$(dirname "$(dirname "$(dirname "$PROJECT_DIR")")")"
|
||||
|
||||
# Control verbosity (set to false to reduce output)
|
||||
VERBOSE=${VERBOSE:-true}
|
||||
|
||||
# Paths
|
||||
MODELSCOPE_CACHE_DIR="$HOME/.cache/modelscope"
|
||||
MNN_MODELS_DIR="$MODELSCOPE_CACHE_DIR/hub/models/MNN"
|
||||
BUILD_64_DIR="$ROOT_PROJECT_DIR/project/android/build_64"
|
||||
PHONE_TEST_DIR="/data/local/tmp/test_model"
|
||||
|
||||
# Functions
|
||||
log_info() {
|
||||
if [[ "$VERBOSE" == "true" ]]; then
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
fi
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
check_requirements() {
|
||||
log_info "Checking requirements..."
|
||||
|
||||
# Check if we're in the right directory
|
||||
if [[ ! -f "app/build.gradle" ]]; then
|
||||
log_error "This script must be run from the project root directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if ADB is available
|
||||
if ! command -v adb &> /dev/null; then
|
||||
log_error "ADB is not installed or not in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if modelscope cache directory exists
|
||||
if [[ ! -d "$MODELSCOPE_CACHE_DIR" ]]; then
|
||||
log_error "ModelScope cache directory not found: $MODELSCOPE_CACHE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if models directory exists (either MNN subdirectory or main models directory)
|
||||
if [[ ! -d "$MNN_MODELS_DIR" ]] && [[ ! -d "$MODELSCOPE_CACHE_DIR/hub/models" ]]; then
|
||||
log_error "Neither MNN models directory nor main models directory found"
|
||||
log_info "Available directories in $MODELSCOPE_CACHE_DIR:"
|
||||
ls -la "$MODELSCOPE_CACHE_DIR" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if build_64 directory exists
|
||||
if [[ ! -d "$BUILD_64_DIR" ]]; then
|
||||
log_error "Build 64 directory not found: $BUILD_64_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Requirements check completed"
|
||||
}
|
||||
|
||||
check_device_connection() {
|
||||
log_info "Checking device connection..."
|
||||
|
||||
# Check if any device is connected
|
||||
if ! adb devices | grep -q "device$"; then
|
||||
log_error "No Android device connected. Please connect a device and enable USB debugging."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get device info
|
||||
DEVICE_ID=$(adb devices | grep "device$" | head -n1 | cut -f1)
|
||||
log_info "Connected device: $DEVICE_ID"
|
||||
|
||||
# Check if device is rooted (needed for /data/local/tmp access)
|
||||
if ! adb shell "su -c 'ls /data/local/tmp'" &> /dev/null; then
|
||||
log_warning "Device may not be rooted. Some operations might fail."
|
||||
fi
|
||||
|
||||
log_success "Device connection verified"
|
||||
}
|
||||
|
||||
setup_phone_directory() {
|
||||
log_info "Setting up phone directory..."
|
||||
|
||||
# Create test directory on phone
|
||||
adb shell "mkdir -p $PHONE_TEST_DIR"
|
||||
adb shell "chmod 755 $PHONE_TEST_DIR"
|
||||
|
||||
log_success "Phone directory setup completed"
|
||||
}
|
||||
|
||||
select_and_push_model() {
|
||||
log_info "Selecting model from models directory..."
|
||||
|
||||
# First try MNN subdirectory, then fall back to main models directory
|
||||
if [[ -d "$MNN_MODELS_DIR" ]]; then
|
||||
MODELS_DIR="$MNN_MODELS_DIR"
|
||||
log_info "Using MNN models directory: $MODELS_DIR"
|
||||
else
|
||||
MODELS_DIR="$MODELSCOPE_CACHE_DIR/hub/models"
|
||||
log_info "MNN subdirectory not found, using main models directory: $MODELS_DIR"
|
||||
fi
|
||||
|
||||
# Debug: show what's actually in the models directory
|
||||
if [[ "$VERBOSE" == "true" ]]; then
|
||||
log_info "Contents of $MODELS_DIR:"
|
||||
ls -la "$MODELS_DIR" 2>/dev/null || true
|
||||
echo "----------------------------------------"
|
||||
fi
|
||||
|
||||
# List available models
|
||||
log_info "Available models in $MODELS_DIR:"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# Get list of model directories (excluding . and .. and the parent directory)
|
||||
MODEL_DIRS=()
|
||||
|
||||
# Get top-level directories, excluding . and .. and the parent directory itself
|
||||
while IFS= read -r -d '' dir; do
|
||||
if [[ "$dir" != "$MODELS_DIR" ]]; then
|
||||
MODEL_DIRS+=("$dir")
|
||||
fi
|
||||
done < <(find "$MODELS_DIR" -maxdepth 1 -type d ! -name "." ! -name ".." -print0 | sort -z)
|
||||
|
||||
# Debug: show what we found
|
||||
if [[ "$VERBOSE" == "true" ]]; then
|
||||
log_info "Found ${#MODEL_DIRS[@]} model directories:"
|
||||
for dir in "${MODEL_DIRS[@]}"; do
|
||||
log_info " Found: $dir"
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ ${#MODEL_DIRS[@]} -eq 0 ]]; then
|
||||
log_error "No model directories found in $MODELS_DIR. Please check your ModelScope cache structure."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Display models with numbers
|
||||
for i in "${!MODEL_DIRS[@]}"; do
|
||||
model_name=$(basename "${MODEL_DIRS[$i]}")
|
||||
echo "$((i+1)). $model_name"
|
||||
done
|
||||
echo "----------------------------------------"
|
||||
|
||||
# Get user selection
|
||||
while true; do
|
||||
read -p "Select a model (1-${#MODEL_DIRS[@]}): " selection
|
||||
if [[ "$selection" =~ ^[0-9]+$ ]] && [[ "$selection" -ge 1 ]] && [[ "$selection" -le "${#MODEL_DIRS[@]}" ]]; then
|
||||
SELECTED_MODEL_DIR="${MODEL_DIRS[$((selection-1))]}"
|
||||
break
|
||||
else
|
||||
echo "Please enter a valid number between 1 and ${#MODEL_DIRS[@]}"
|
||||
fi
|
||||
done
|
||||
|
||||
SELECTED_MODEL_NAME=$(basename "$SELECTED_MODEL_DIR")
|
||||
log_info "Selected model: $SELECTED_MODEL_NAME"
|
||||
|
||||
# Push the selected model files
|
||||
log_info "Pushing all files for $SELECTED_MODEL_NAME..."
|
||||
|
||||
# Push all files from the selected directory
|
||||
MODEL_FILES=$(find "$SELECTED_MODEL_DIR" -type f 2>/dev/null)
|
||||
|
||||
if [[ -z "$MODEL_FILES" ]]; then
|
||||
log_warning "No files found in $SELECTED_MODEL_NAME directory"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Push each file
|
||||
for file in $MODEL_FILES; do
|
||||
filename=$(basename "$file")
|
||||
log_info "Pushing $filename..."
|
||||
adb push "$file" "$PHONE_TEST_DIR/"
|
||||
done
|
||||
|
||||
log_success "Model files for $SELECTED_MODEL_NAME pushed to phone"
|
||||
|
||||
# Show what files were pushed
|
||||
if [[ "$VERBOSE" == "true" ]]; then
|
||||
log_info "Files pushed for $SELECTED_MODEL_NAME:"
|
||||
adb shell "ls -la $PHONE_TEST_DIR/*" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
push_test_binaries() {
|
||||
log_info "Pushing test binaries from build_64 directory..."
|
||||
|
||||
# Check for llm_demo binary
|
||||
if [[ -f "$BUILD_64_DIR/llm_demo" ]]; then
|
||||
log_info "Pushing llm_demo binary..."
|
||||
adb push "$BUILD_64_DIR/llm_demo" "$PHONE_TEST_DIR/"
|
||||
adb shell "chmod +x $PHONE_TEST_DIR/llm_demo"
|
||||
else
|
||||
log_warning "llm_demo binary not found in $BUILD_64_DIR"
|
||||
fi
|
||||
|
||||
# Push .so files
|
||||
SO_FILES=$(find "$BUILD_64_DIR" -name "*.so" 2>/dev/null)
|
||||
if [[ -n "$SO_FILES" ]]; then
|
||||
log_info "Pushing .so files..."
|
||||
for file in $SO_FILES; do
|
||||
filename=$(basename "$file")
|
||||
log_info "Pushing $filename..."
|
||||
adb push "$file" "$PHONE_TEST_DIR/"
|
||||
done
|
||||
else
|
||||
log_warning "No .so files found in $BUILD_64_DIR"
|
||||
fi
|
||||
|
||||
# Push other important files
|
||||
for file in "config.json" "tokenizer.json" "tokenizer_config.json" "special_tokens_map.json"; do
|
||||
if [[ -f "$BUILD_64_DIR/$file" ]]; then
|
||||
log_info "Pushing $file..."
|
||||
adb push "$BUILD_64_DIR/$file" "$PHONE_TEST_DIR/"
|
||||
fi
|
||||
done
|
||||
|
||||
# Push libMNN.so from the correct location
|
||||
if [[ -f "$BUILD_64_DIR/libMNN.so" ]]; then
|
||||
log_info "Found libMNN.so in build directory"
|
||||
else
|
||||
log_error "libMNN.so not found at $BUILD_64_DIR/libMNN.so. Please ensure it's built."
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "Test binaries pushed to phone"
|
||||
}
|
||||
|
||||
run_test() {
|
||||
log_info "Running test on phone..."
|
||||
|
||||
# Create prompt file
|
||||
adb shell "echo 'hello' > $PHONE_TEST_DIR/prompt"
|
||||
|
||||
# Find config file
|
||||
CONFIG_FILE=""
|
||||
for config in "config.json" "model_config.json" "config.ini"; do
|
||||
if adb shell "test -f $PHONE_TEST_DIR/$config" 2>/dev/null; then
|
||||
CONFIG_FILE="$config"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Set LD_LIBRARY_PATH to include current directory for .so files
|
||||
if [[ -z "$CONFIG_FILE" ]]; then
|
||||
log_warning "No config file found, trying to run without config..."
|
||||
adb shell "cd $PHONE_TEST_DIR && export LD_LIBRARY_PATH=./ && ./llm_demo prompt"
|
||||
else
|
||||
log_info "Using config file: $CONFIG_FILE"
|
||||
adb shell "cd $PHONE_TEST_DIR && export LD_LIBRARY_PATH=./ && ./llm_demo $CONFIG_FILE prompt"
|
||||
fi
|
||||
|
||||
log_success "Test execution completed"
|
||||
}
|
||||
|
||||
list_phone_files() {
|
||||
if [[ "$VERBOSE" == "true" ]]; then
|
||||
log_info "Listing files on phone..."
|
||||
adb shell "ls -la $PHONE_TEST_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
verify_library_dependencies() {
|
||||
log_info "Verifying library dependencies..."
|
||||
|
||||
# Check if libMNN.so is present
|
||||
if adb shell "test -f $PHONE_TEST_DIR/libMNN.so" 2>/dev/null; then
|
||||
log_success "libMNN.so found on phone"
|
||||
else
|
||||
log_error "libMNN.so not found on phone - this will cause execution to fail"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if llm_demo is executable
|
||||
if adb shell "test -x $PHONE_TEST_DIR/llm_demo" 2>/dev/null; then
|
||||
log_success "llm_demo is executable on phone"
|
||||
else
|
||||
log_error "llm_demo is not executable on phone"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_success "Library dependencies verified"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
log_info "Cleaning up..."
|
||||
# Optionally remove test directory from phone
|
||||
read -p "Do you want to remove the test directory from phone? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
adb shell "rm -rf $PHONE_TEST_DIR"
|
||||
log_success "Phone test directory removed"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
log_info "Starting Model Test Script for $PROJECT_NAME"
|
||||
|
||||
check_requirements
|
||||
check_device_connection
|
||||
setup_phone_directory
|
||||
select_and_push_model
|
||||
push_test_binaries
|
||||
list_phone_files
|
||||
verify_library_dependencies
|
||||
run_test
|
||||
|
||||
log_success "Model test script completed successfully"
|
||||
|
||||
cleanup
|
||||
}
|
||||
|
||||
# Handle script interruption
|
||||
trap 'log_error "Script interrupted"; exit 1' INT TERM
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
|
@ -144,7 +144,7 @@ build_googleplay_release() {
|
|||
./gradlew bundleGoogleplayRelease
|
||||
|
||||
# Copy AAB to output directory
|
||||
AAB_PATH="$BUILD_DIR/outputs/bundle/googleplay/release/app-googleplay-release.aab"
|
||||
AAB_PATH="$BUILD_DIR/outputs/bundle/googleplayRelease/app-googleplay-release.aab"
|
||||
if [[ -f "$AAB_PATH" ]]; then
|
||||
cp "$AAB_PATH" "$GOOGLE_PLAY_DIR/"
|
||||
log_success "Google Play release AAB built: $GOOGLE_PLAY_DIR/app-googleplay-release.aab"
|
||||
|
|
Loading…
Reference in New Issue