Skip to content

Commit 59e97f0

Browse files
committed
Fix: Model installation, database sync, and DataHub issues
- Fix stubbed ModelManager.loadGenerationModel() and generateStreaming() to properly route to OpenRouter/GGUF providers - Add GGUFDatabaseModel to ModelData conversion function for syncing between ai-engine and ai-module databases - Fix OnlineModelStoreViewModel to refresh installed models after download completion and sync databases - Implement DataPackScreenViewModel.loadDataPacks() with DataPackProvider - Fix DataHub header to match PluginHub styling (TopAppBar with consistent Home button design)
1 parent 6c7aae7 commit 59e97f0

8 files changed

Lines changed: 330 additions & 73 deletions

File tree

ai-module/src/main/java/com/nano/ai_module/model/ModelsData.kt

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,42 @@ fun ModelData.getFormattedSize(): String? {
165165
}
166166

167167
// Required companion object for fromJson extension
168-
fun ModelData.create() = ModelData()
168+
fun ModelData.create() = ModelData()
169+
170+
/**
171+
* Creates ModelData from JSON string for deserialization.
172+
*/
173+
fun ModelData.Companion.fromJson(jsonString: String): ModelData {
174+
val json = JSONObject(jsonString)
175+
return ModelData(
176+
id = json.optString("id", java.util.UUID.randomUUID().toString()),
177+
modelName = json.optString("modelName", ""),
178+
providerName = json.optString("providerName", ""),
179+
modelType = try { ModelType.valueOf(json.optString("modelType", "TEXT")) } catch (e: Exception) { ModelType.TEXT },
180+
modelPath = json.optString("modelPath", ""),
181+
architecture = json.optString("architecture", ""),
182+
threads = json.optInt("threads", (Runtime.getRuntime().availableProcessors().coerceAtLeast(2)) / 2),
183+
gpuLayers = json.optInt("gpuLayers", 0),
184+
useMMAP = json.optBoolean("useMMAP", true),
185+
useMLOCK = json.optBoolean("useMLOCK", false),
186+
ctxSize = json.optInt("ctxSize", 4096),
187+
temp = json.optDouble("temp", 0.7).toFloat(),
188+
topK = json.optInt("topK", 20),
189+
topP = json.optDouble("topP", 0.5).toFloat(),
190+
minP = json.optDouble("minP", 0.0).toFloat(),
191+
maxTokens = json.optInt("maxTokens", 2048),
192+
mirostat = json.optInt("mirostat", 1),
193+
mirostatTau = json.optDouble("mirostatTau", 5.0).toFloat(),
194+
mirostatEta = json.optDouble("mirostatEta", 0.1).toFloat(),
195+
seed = json.optInt("seed", -1),
196+
isImported = json.optBoolean("isImported", false),
197+
modelUrl = json.optString("modelUrl", null),
198+
isToolCalling = json.optBoolean("isToolCalling", false),
199+
systemPrompt = json.optString("systemPrompt", "You are a helpful assistant."),
200+
chatTemplate = json.optString("chatTemplate", null)
201+
)
202+
}
203+
204+
// Companion object for ModelData
205+
val ModelData.Companion: ModelDataCompanion get() = ModelDataCompanion
206+
object ModelDataCompanion

ai-module/src/main/java/com/nano/ai_module/workers/ModelManager.kt

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,18 @@ object ModelManager {
142142
suspend fun loadGenerationModel(
143143
modelData: ModelData, onLoaded: (LoadState) -> Unit
144144
): Result<Unit> = withContext(Dispatchers.IO) {
145-
return@withContext Result.success(Unit)
146-
// when (modelData.providerName) {
147-
// ModelProvider.OpenRouter.toString() -> loadOpenRouterModel(modelData, onLoaded)
148-
// ModelProvider.LocalGGUF.toString() -> loadGGUFModel(modelData, onLoaded)
149-
// else -> Result.failure(IllegalArgumentException("Unknown provider: ${modelData.providerName}"))
150-
// }
145+
return@withContext when (modelData.providerName) {
146+
"OPEN_ROUTER", "OpenRouter" -> loadOpenRouterModel(modelData, onLoaded)
147+
"GGUF", "LocalGGUF" -> loadGGUFModel(modelData, onLoaded)
148+
else -> {
149+
// Default to GGUF if model path exists
150+
if (modelData.modelPath.isNotEmpty()) {
151+
loadGGUFModel(modelData, onLoaded)
152+
} else {
153+
Result.failure(IllegalArgumentException("Unknown provider: ${modelData.providerName}"))
154+
}
155+
}
156+
}
151157
}
152158

153159
private fun loadOpenRouterModel(
@@ -329,32 +335,44 @@ object ModelManager {
329335
): String {
330336
val model = _currentModel.value
331337

332-
return ""
333-
// return when (model.providerName) {
334-
// ModelProvider.OpenRouter.toString() -> {
335-
// generateOpenRouter(
336-
// modelId = model.modelUrl ?: "",
337-
// prompt = prompt,
338-
// systemPrompt = model.systemPrompt,
339-
// gen = gen,
340-
// toolJson = toolJson,
341-
// onToolCalled = onToolCalled,
342-
// onToken = onToken
343-
// )
344-
// }
345-
//
346-
// ModelProvider.LocalGGUF.toString() -> {
347-
// generateGGUF(
348-
// prompt = prompt,
349-
// gen = gen,
350-
// toolJson = toolJson,
351-
// onToolCalled = onToolCalled,
352-
// onToken = onToken
353-
// )
354-
// }
355-
//
356-
// else -> throw IllegalStateException("Unknown provider: ${model.providerName}")
357-
// }
338+
return when (model.providerName) {
339+
"OPEN_ROUTER", "OpenRouter" -> {
340+
generateOpenRouter(
341+
modelId = model.modelUrl ?: "",
342+
prompt = prompt,
343+
systemPrompt = model.systemPrompt,
344+
gen = gen,
345+
toolJson = toolJson,
346+
onToolCalled = onToolCalled,
347+
onToken = onToken
348+
)
349+
}
350+
351+
"GGUF", "LocalGGUF" -> {
352+
generateGGUF(
353+
prompt = prompt,
354+
gen = gen,
355+
toolJson = toolJson,
356+
onToolCalled = onToolCalled,
357+
onToken = onToken
358+
)
359+
}
360+
361+
else -> {
362+
// Default to GGUF if model is loaded
363+
if (model.modelPath.isNotEmpty()) {
364+
generateGGUF(
365+
prompt = prompt,
366+
gen = gen,
367+
toolJson = toolJson,
368+
onToolCalled = onToolCalled,
369+
onToken = onToken
370+
)
371+
} else {
372+
throw IllegalStateException("No model loaded or unknown provider: ${model.providerName}")
373+
}
374+
}
375+
}
358376
}
359377

360378
private suspend fun generateOpenRouter(
@@ -415,12 +433,17 @@ object ModelManager {
415433

416434
fun stopGeneration() {
417435
val model = _currentModel.value
418-
// when (model.providerName) {
419-
// ModelProvider.OpenRouter.toString() -> openRouterExecutor?.stopGeneration()
420-
// ModelProvider.LocalGGUF.toString() -> {
421-
// service?.stopTextGeneration()
422-
// }
423-
// }
436+
when (model.providerName) {
437+
"OPEN_ROUTER", "OpenRouter" -> openRouterExecutor?.stopGeneration()
438+
"GGUF", "LocalGGUF" -> {
439+
service?.stopTextGeneration()
440+
}
441+
else -> {
442+
// Try to stop both
443+
openRouterExecutor?.stopGeneration()
444+
service?.stopTextGeneration()
445+
}
446+
}
424447
isGenerating.value = false
425448
}
426449

@@ -522,9 +545,9 @@ object ModelManager {
522545

523546
fun setSystemPrompt(prompt: String) {
524547
val model = _currentModel.value
525-
// when (model.providerName) {
526-
// ModelProvider.LocalGGUF.toString() -> service?.setSystemPrompt(prompt)
527-
// }
548+
when (model.providerName) {
549+
"GGUF", "LocalGGUF" -> service?.setSystemPrompt(prompt)
550+
}
528551
_currentModel.value = model.copy(systemPrompt = prompt)
529552
}
530553

app/src/main/java/com/nano/ai/activity/DatahubActivity.kt

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,24 @@ import android.os.Bundle
55
import androidx.activity.ComponentActivity
66
import androidx.activity.compose.setContent
77
import androidx.activity.enableEdgeToEdge
8-
import androidx.compose.foundation.layout.Arrangement
9-
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.foundation.layout.Spacer
9+
import androidx.compose.foundation.layout.padding
10+
import androidx.compose.foundation.layout.width
1011
import androidx.compose.material.icons.Icons
1112
import androidx.compose.material.icons.outlined.Home
12-
import androidx.compose.material3.CenterAlignedTopAppBar
13+
import androidx.compose.material3.Button
14+
import androidx.compose.material3.ButtonDefaults
1315
import androidx.compose.material3.ExperimentalMaterial3Api
1416
import androidx.compose.material3.Icon
15-
import androidx.compose.material3.IconButton
1617
import androidx.compose.material3.MaterialTheme
1718
import androidx.compose.material3.Scaffold
1819
import androidx.compose.material3.Text
20+
import androidx.compose.material3.TopAppBar
1921
import androidx.compose.material3.TopAppBarDefaults
20-
import androidx.compose.ui.Alignment
21-
import androidx.compose.ui.res.painterResource
22+
import androidx.compose.material3.rememberTopAppBarState
23+
import androidx.compose.ui.Modifier
24+
import androidx.compose.ui.text.font.FontWeight
2225
import androidx.compose.ui.unit.dp
23-
import com.nano.ai.R
2426
import com.nano.ai.ui.screens.hub.DataHubScreen
2527
import com.nano.ai.ui.theme.NeuroVerseTheme
2628
import com.nano.ai.ui.theme.rDP
@@ -34,31 +36,34 @@ class DatahubActivity : ComponentActivity() {
3436
NeuroVerseTheme {
3537
Scaffold(
3638
topBar = {
37-
CenterAlignedTopAppBar(title = {
38-
Row(
39-
verticalAlignment = Alignment.CenterVertically,
40-
horizontalArrangement = Arrangement.spacedBy(
41-
rDP(10.dp)
39+
TopAppBar(
40+
title = {
41+
Text(
42+
"Data Hub",
43+
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.SemiBold)
4244
)
43-
) {
44-
Icon(
45-
painterResource(R.drawable.database_zap),
46-
contentDescription = null
47-
)
48-
Text("Data Packs")
49-
}
50-
}, actions = {
51-
IconButton(onClick = {
52-
startActivity(
53-
Intent(
54-
this@DatahubActivity,
55-
MainActivity::class.java
45+
},
46+
actions = {
47+
Button(
48+
onClick = {
49+
val intent = Intent(this@DatahubActivity, MainActivity::class.java).apply {
50+
putExtra("nav", true)
51+
}
52+
startActivity(intent)
53+
},
54+
modifier = Modifier.padding(end = rDP(12.dp)),
55+
colors = ButtonDefaults.buttonColors(
56+
containerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f),
57+
contentColor = MaterialTheme.colorScheme.primary
5658
)
57-
)
58-
}) {
59-
Icon(Icons.Outlined.Home, "Home")
60-
}
61-
}, colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.primaryContainer))
59+
) {
60+
Icon(Icons.Outlined.Home, "Home")
61+
Spacer(Modifier.width(rDP(3.dp)))
62+
Text("Home")
63+
}
64+
},
65+
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
66+
)
6267
}) {
6368
DataHubScreen(paddingValues = it)
6469
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.nano.ai.data
2+
3+
import com.nano.ai.model.DataPack
4+
5+
/**
6+
* Provider for available data packs
7+
* Can be replaced with Firebase/API data later
8+
*/
9+
object DataPackProvider {
10+
11+
/**
12+
* Get list of available data packs
13+
* This can be replaced with Firebase fetch or API call
14+
*/
15+
fun getDataPacks(): List<DataPack> {
16+
return listOf(
17+
DataPack(
18+
name = "General Knowledge",
19+
description = "Comprehensive knowledge base covering science, history, geography, and more.",
20+
size = "150 MB",
21+
author = "Nano.ai Team",
22+
issued = "2025-01-01",
23+
license_text = "Free for personal use",
24+
license_type = "MIT",
25+
link = "https://example.com/datapacks/general-knowledge.vecx"
26+
),
27+
DataPack(
28+
name = "Programming Reference",
29+
description = "Programming languages documentation including Python, JavaScript, Kotlin, and more.",
30+
size = "200 MB",
31+
author = "Nano.ai Team",
32+
issued = "2025-01-01",
33+
license_text = "Free for personal use",
34+
license_type = "MIT",
35+
link = "https://example.com/datapacks/programming-ref.vecx"
36+
),
37+
DataPack(
38+
name = "Medical Encyclopedia",
39+
description = "Medical terminology, conditions, treatments, and drug information.",
40+
size = "180 MB",
41+
author = "Nano.ai Team",
42+
issued = "2025-01-01",
43+
license_text = "For educational purposes only",
44+
license_type = "CC BY-NC",
45+
link = "https://example.com/datapacks/medical-encyclopedia.vecx"
46+
),
47+
DataPack(
48+
name = "Legal Documents",
49+
description = "Legal terminology, contract templates, and common legal procedures.",
50+
size = "120 MB",
51+
author = "Nano.ai Team",
52+
issued = "2025-01-01",
53+
license_text = "For reference only, not legal advice",
54+
license_type = "CC BY",
55+
link = "https://example.com/datapacks/legal-docs.vecx"
56+
),
57+
DataPack(
58+
name = "Scientific Papers",
59+
description = "Summaries and abstracts from various scientific journals and research papers.",
60+
size = "250 MB",
61+
author = "Nano.ai Team",
62+
issued = "2025-01-01",
63+
license_text = "Open access content",
64+
license_type = "CC BY",
65+
link = "https://example.com/datapacks/scientific-papers.vecx"
66+
)
67+
)
68+
}
69+
}

0 commit comments

Comments
 (0)