Skip to content

Commit 36db37b

Browse files
committed
feat(android-app): ChatGPT-style chat redesign and full LoRA adapter UI
Redesign chat screen to clean ChatGPT-like layout (no bubbles for assistant, solid user bubbles) and add complete LoRA adapter management: picker sheet, manager screen, model badges, real adapter registration from Void2377/Qwen.
1 parent 95d73fd commit 36db37b

13 files changed

Lines changed: 1273 additions & 301 deletions

File tree

examples/android/RunAnywhereAI/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
android:roundIcon="@mipmap/ic_launcher_round"
2727
android:supportsRtl="true"
2828
android:theme="@style/Theme.RunAnywhereAI"
29+
android:windowSoftInputMode="adjustResize"
2930
android:largeHeap="true"
3031
android:usesCleartextTraffic="false"
3132
tools:targetApi="35">

examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/MainActivity.kt

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -58,31 +58,26 @@ class MainActivity : ComponentActivity() {
5858
val initState by app.initializationState.collectAsState()
5959
val scope = rememberCoroutineScope()
6060

61-
Surface(
62-
modifier = Modifier.fillMaxSize(),
63-
color = MaterialTheme.colorScheme.background,
64-
) {
65-
when (initState) {
66-
is SDKInitializationState.Loading -> {
67-
InitializationLoadingView()
68-
}
61+
when (initState) {
62+
is SDKInitializationState.Loading -> {
63+
InitializationLoadingView()
64+
}
6965

70-
is SDKInitializationState.Error -> {
71-
val error = (initState as SDKInitializationState.Error).error
72-
InitializationErrorView(
73-
error = error,
74-
onRetry = {
75-
scope.launch {
76-
app.retryInitialization()
77-
}
78-
},
79-
)
80-
}
66+
is SDKInitializationState.Error -> {
67+
val error = (initState as SDKInitializationState.Error).error
68+
InitializationErrorView(
69+
error = error,
70+
onRetry = {
71+
scope.launch {
72+
app.retryInitialization()
73+
}
74+
},
75+
)
76+
}
8177

82-
is SDKInitializationState.Ready -> {
83-
Log.i("MainActivity", "App is ready to use!")
84-
AppNavigation()
85-
}
78+
is SDKInitializationState.Ready -> {
79+
Log.i("MainActivity", "App is ready to use!")
80+
AppNavigation()
8681
}
8782
}
8883
}

examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/data/ModelList.kt

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import com.runanywhere.sdk.core.onnx.ONNX
66
import com.runanywhere.sdk.core.types.InferenceFramework
77
import com.runanywhere.sdk.llm.llamacpp.LlamaCPP
88
import com.runanywhere.sdk.public.RunAnywhere
9+
import com.runanywhere.sdk.public.extensions.LoraAdapterCatalogEntry
910
import com.runanywhere.sdk.public.extensions.ModelCompanionFile
1011
import com.runanywhere.sdk.public.extensions.Models.ModelCategory
1112
import com.runanywhere.sdk.public.extensions.Models.ModelFileDescriptor
13+
import com.runanywhere.sdk.public.extensions.registerLoraAdapter
1214
import com.runanywhere.sdk.public.extensions.registerModel
1315
import com.runanywhere.sdk.public.extensions.registerMultiFileModel
1416

@@ -32,15 +34,15 @@ object ModelList {
3234
AppModel(id = "qwen2.5-0.5b-instruct-q6_k", name = "Qwen 2.5 0.5B Instruct Q6_K",
3335
url = "https://huggingface.co/Triangle104/Qwen2.5-0.5B-Instruct-Q6_K-GGUF/resolve/main/qwen2.5-0.5b-instruct-q6_k.gguf",
3436
framework = InferenceFramework.LLAMA_CPP, category = ModelCategory.LANGUAGE,
35-
memoryRequirement = 600_000_000, supportsLoraAdapters = true),
37+
memoryRequirement = 600_000_000),
3638
AppModel(id = "lfm2-350m-q4_k_m", name = "LiquidAI LFM2 350M Q4_K_M",
3739
url = "https://huggingface.co/LiquidAI/LFM2-350M-GGUF/resolve/main/LFM2-350M-Q4_K_M.gguf",
3840
framework = InferenceFramework.LLAMA_CPP, category = ModelCategory.LANGUAGE,
39-
memoryRequirement = 250_000_000),
41+
memoryRequirement = 250_000_000, supportsLoraAdapters = true),
4042
AppModel(id = "lfm2-350m-q8_0", name = "LiquidAI LFM2 350M Q8_0",
4143
url = "https://huggingface.co/LiquidAI/LFM2-350M-GGUF/resolve/main/LFM2-350M-Q8_0.gguf",
4244
framework = InferenceFramework.LLAMA_CPP, category = ModelCategory.LANGUAGE,
43-
memoryRequirement = 400_000_000),
45+
memoryRequirement = 400_000_000, supportsLoraAdapters = true),
4446
AppModel(id = "lfm2-1.2b-tool-q4_k_m", name = "LiquidAI LFM2 1.2B Tool Q4_K_M",
4547
url = "https://huggingface.co/LiquidAI/LFM2-1.2B-Tool-GGUF/resolve/main/LFM2-1.2B-Tool-Q4_K_M.gguf",
4648
framework = InferenceFramework.LLAMA_CPP, category = ModelCategory.LANGUAGE,
@@ -81,6 +83,60 @@ object ModelList {
8183
)),
8284
)
8385

86+
// LoRA Adapters (from Void2377/Qwen on HuggingFace — real standalone LoRA GGUF files)
87+
private val loraAdapters = listOf(
88+
LoraAdapterCatalogEntry(
89+
id = "chat-assistant-lora",
90+
name = "Chat Assistant",
91+
description = "Enhances conversational chat ability",
92+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/chat_assistant-lora-Q8_0.gguf",
93+
filename = "chat_assistant-lora-Q8_0.gguf",
94+
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
95+
fileSize = 690_176,
96+
defaultScale = 1.0f,
97+
),
98+
LoraAdapterCatalogEntry(
99+
id = "summarizer-lora",
100+
name = "Summarizer",
101+
description = "Specialized for text summarization tasks",
102+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/summarizer-lora-Q8_0.gguf",
103+
filename = "summarizer-lora-Q8_0.gguf",
104+
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
105+
fileSize = 690_176,
106+
defaultScale = 1.0f,
107+
),
108+
LoraAdapterCatalogEntry(
109+
id = "translator-lora",
110+
name = "Translator",
111+
description = "Improves translation between languages",
112+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/translator-lora-Q8_0.gguf",
113+
filename = "translator-lora-Q8_0.gguf",
114+
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
115+
fileSize = 690_176,
116+
defaultScale = 1.0f,
117+
),
118+
LoraAdapterCatalogEntry(
119+
id = "sentiment-lora",
120+
name = "Sentiment Analysis",
121+
description = "Fine-tuned for sentiment analysis tasks",
122+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/sentiment-lora-Q8_0.gguf",
123+
filename = "sentiment-lora-Q8_0.gguf",
124+
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
125+
fileSize = 690_176,
126+
defaultScale = 1.0f,
127+
),
128+
LoraAdapterCatalogEntry(
129+
id = "uncensored-chat-lora",
130+
name = "Uncensored Chat",
131+
description = "Removes safety guardrails for uncensored responses",
132+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/uncensored_chat-lora-Q8_0.gguf",
133+
filename = "uncensored_chat-lora-Q8_0.gguf",
134+
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
135+
fileSize = 1_372_160,
136+
defaultScale = 1.0f,
137+
),
138+
)
139+
84140
// VLM
85141
private val vlmModels = listOf(
86142
AppModel(id = "smolvlm-500m-instruct-q8_0", name = "SmolVLM 500M Instruct",
@@ -146,6 +202,12 @@ object ModelList {
146202
}
147203
}
148204
Log.i(TAG, "VLM models registered (${vlmModels.size})")
205+
206+
// Register LoRA adapters
207+
for (adapter in loraAdapters) {
208+
RunAnywhere.registerLoraAdapter(adapter)
209+
}
210+
Log.i(TAG, "LoRA adapters registered (${loraAdapters.size})")
149211
Log.i(TAG, "All models registered")
150212
}
151213
}

0 commit comments

Comments
 (0)