Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,13 @@ public static boolean isMTMD_ImageModel(String name) {

public static boolean isAudioFile(String filename) {
//naive method
//IMPORTANT: must match what mtmd-helper actually supports.
//mtmd-helper.cpp uses miniaudio to decode audio and only accepts
//wav/mp3/flac. aac and ac3 (e.g. from m4a containers) are NOT
//decoded by miniaudio and will be rejected inside mtmd, so we
//should not even route them to the audio MTMD path. If a future
//build adds aac support, add it here and update the list of
//supported audio types accordingly.
String suffix = filename.substring(filename.lastIndexOf(".") + 1);
if (suffix.contains("wav")) {
return true;
Expand All @@ -325,11 +332,7 @@ public static boolean isAudioFile(String filename) {
return true;
}

if (suffix.contains("aac")) {
return true;
}

if (suffix.contains("ac3")) {
if (suffix.contains("flac")) {
return true;
}

Expand Down
18 changes: 18 additions & 0 deletions android/kantvplayer-lib/src/main/java/kantvai/ai/ggmljava.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,24 @@ public final class ggmljava {

public static native void llm_finalize();

/**
* Release the llama backend (DSP + quant tables) installed at JNI init.
* Pair of {@link #backendInit()}. Safe to call multiple times. The
* intended call site is AIResearchFragment.onDestroy() so the Hexagon
* DSP gets released on activity teardown instead of holding resources
* until the OS kills the process.
*/
public static native void backendCleanup();

/**
* Release the currently loaded model (and mtmd/vision context if any).
* Subsequent inference calls will trigger a fresh 4GB read from disk
* - use this to free RAM when the user switches models in
* LLMSettingFragment, or to drop the model on activity teardown
* alongside {@link #backendCleanup()}. Idempotent.
*/
public static native void unloadModel();

// ============================================================================================
// LLM/MTMD benchmark singleton state queries (UI helpers).
//
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ public class LLMSettingFragment extends BaseSettingsFragment {

private LLMSettingHeaderPreference mHeaderPreference;

// Tracks the model path that was last seen by the pref.llmmodel
// change listener. The listener fires both for the user's dropdown
// choice AND for the "heal on access" setValue() during fragment
// creation (see line 133), so we need to compare against the last
// seen value to avoid spurious unloadModel() calls.
private String mLastSelectedModelPath = null;


@Override
public String getTitle() {
Expand Down Expand Up @@ -221,6 +228,34 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin
KANTVLog.g(TAG, "LLM model name: " + KANTVAIModelMgr.getInstance().getModelName(mSettings.getLLMModel()));
String modelPath = KANTVUtils.getSDCardDataPath() + KANTVAIModelMgr.getInstance().getModelName(mSettings.getLLMModel());
KANTVLog.g(TAG, "modelPath:" + modelPath);

// If the user actually switched to a *different* model
// (not just the heal-on-access setValue that fires
// during fragment creation) and no inference is
// currently running, unload the model on the native
// side right now.
//
// Why here and not in ensure_model_loaded: the C++
// cache-miss path also has an unload + 500ms sleep
// (Phase 2.5 / A), so the safety net is in place.
// The point of doing it here is *latency* - by the
// time the user navigates back to AI Research and
// fires an inference, the 4GB has already been
// released and the page-reclaimer has had seconds
// (not milliseconds) to give those pages back to
// the OS. The inference itself then takes the
// cache-miss path's fast new-load branch instead
// of unloading+loading in one go (which used to
// OOM on a 12GB OnePlus, see project memory).
if (mLastSelectedModelPath != null
&& !mLastSelectedModelPath.equals(modelPath)
&& !ggmljava.llm_is_running_state()) {
KANTVLog.j(TAG, "Model changed from '"
+ mLastSelectedModelPath + "' to '" + modelPath
+ "', unloading old model proactively");
ggmljava.unloadModel();
}
mLastSelectedModelPath = modelPath;
} catch (Exception ex) {
KANTVLog.g(TAG, "error: " + ex.toString());
KANTVUtils.showMsgBox(mActivity, "error: " + ex.toString());
Expand Down
Loading
Loading