diff --git a/examples/llama.android/app/src/main/java/com/example/llama/revamp/data/repository/ModelRepository.kt b/examples/llama.android/app/src/main/java/com/example/llama/revamp/data/repository/ModelRepository.kt new file mode 100644 index 0000000000..cf372f9d70 --- /dev/null +++ b/examples/llama.android/app/src/main/java/com/example/llama/revamp/data/repository/ModelRepository.kt @@ -0,0 +1,51 @@ +package com.example.llama.revamp.data.repository + +import android.content.Context +import android.net.Uri +import com.example.llama.revamp.data.model.ModelInfo +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton + +interface ModelRepository { + suspend fun getModels(): List + suspend fun deleteModel(modelId: String) + suspend fun deleteModels(modelIds: Collection) + suspend fun importModel(uri: Uri): ModelInfo + suspend fun getStorageMetrics(): StorageMetrics +} + +@Singleton +class ModelRepositoryImpl @Inject constructor( + @ApplicationContext private val context: Context, + // TODO-han.yin: Add model DAO +) : ModelRepository { + + override suspend fun getModels(): List { + // In a real implementation, this would load from database + return ModelInfo.getSampleModels() + } + + override suspend fun deleteModel(modelId: String) { + // Stub - would delete from filesystem and database + } + + override suspend fun deleteModels(modelIds: Collection) { + // Stub - would delete from filesystem and database + } + + override suspend fun importModel(uri: Uri): ModelInfo { + // Stub - would copy file and extract metadata + return ModelInfo.getSampleModels().first() + } + + override suspend fun getStorageMetrics(): StorageMetrics { + // Stub - would calculate from actual storage + return StorageMetrics(14.6f, 32.0f) + } +} + +data class StorageMetrics( + val usedGB: Float, + val totalGB: Float +) diff --git a/examples/llama.android/app/src/main/java/com/example/llama/revamp/di/AppModule.kt b/examples/llama.android/app/src/main/java/com/example/llama/revamp/di/AppModule.kt index af4073e496..da1b1306a4 100644 --- a/examples/llama.android/app/src/main/java/com/example/llama/revamp/di/AppModule.kt +++ b/examples/llama.android/app/src/main/java/com/example/llama/revamp/di/AppModule.kt @@ -2,8 +2,11 @@ package com.example.llama.revamp.di import android.content.Context import com.example.llama.revamp.data.local.AppDatabase +import com.example.llama.revamp.data.repository.ModelRepository +import com.example.llama.revamp.data.repository.ModelRepositoryImpl import com.example.llama.revamp.engine.InferenceEngine import com.example.llama.revamp.monitoring.PerformanceMonitor +import dagger.Binds import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -13,19 +16,24 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -object AppModule { +abstract class AppModule { - @Provides - @Singleton - fun provideInferenceEngine() = InferenceEngine() + @Binds + abstract fun bindsModelsRepository(impl: ModelRepositoryImpl): ModelRepository - @Provides - @Singleton - fun providePerformanceMonitor(@ApplicationContext context: Context) = PerformanceMonitor(context) + companion object { + @Provides + @Singleton + fun provideInferenceEngine() = InferenceEngine() - @Provides - fun provideAppDatabase(@ApplicationContext context: Context) = AppDatabase.getDatabase(context) + @Provides + @Singleton + fun providePerformanceMonitor(@ApplicationContext context: Context) = PerformanceMonitor(context) - @Provides - fun providesSystemPromptDao(appDatabase: AppDatabase) = appDatabase.systemPromptDao() + @Provides + fun provideAppDatabase(@ApplicationContext context: Context) = AppDatabase.getDatabase(context) + + @Provides + fun providesSystemPromptDao(appDatabase: AppDatabase) = appDatabase.systemPromptDao() + } } diff --git a/examples/llama.android/app/src/main/java/com/example/llama/revamp/viewmodel/ModelsManagementViewModel.kt b/examples/llama.android/app/src/main/java/com/example/llama/revamp/viewmodel/ModelsManagementViewModel.kt new file mode 100644 index 0000000000..34f7330275 --- /dev/null +++ b/examples/llama.android/app/src/main/java/com/example/llama/revamp/viewmodel/ModelsManagementViewModel.kt @@ -0,0 +1,119 @@ +package com.example.llama.revamp.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.llama.revamp.data.model.ModelInfo +import com.example.llama.revamp.data.repository.ModelRepository +import com.example.llama.revamp.data.repository.StorageMetrics +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ModelsManagementViewModel @Inject constructor( + private val modelRepository: ModelRepository +) : ViewModel() { + + // Sort order state + private val _sortOrder = MutableStateFlow(ModelSortOrder.NAME_ASC) + val sortOrder: StateFlow = _sortOrder.asStateFlow() + + // Available models + private val _availableModels = MutableStateFlow>(emptyList()) + val availableModels: StateFlow> = _availableModels.asStateFlow() + + // Storage metrics + private val _storageMetrics = MutableStateFlow(StorageMetrics(0f, 0f)) + val storageMetrics: StateFlow = _storageMetrics.asStateFlow() + + init { + // Initial data load + viewModelScope.launch { + loadModels() + loadStorageMetrics() + } + + // Observe sort order changes and apply sorting + viewModelScope.launch { + sortOrder.collect { order -> sortModels(order) } + } + } + + private fun loadModels() { + // TODO-han.yin: Stub for now. Would load from the repository + _availableModels.value = ModelInfo.getSampleModels() + sortModels(_sortOrder.value) + } + + private fun loadStorageMetrics() { + // TODO-han.yin: Stub for now. Would load from storage + _storageMetrics.value = StorageMetrics(14.6f, 32.0f) + } + + private fun sortModels(order: ModelSortOrder) { + val sorted = when (order) { + ModelSortOrder.NAME_ASC -> _availableModels.value.sortedBy { it.name } + ModelSortOrder.NAME_DESC -> _availableModels.value.sortedByDescending { it.name } + ModelSortOrder.SIZE_ASC -> _availableModels.value.sortedBy { it.sizeInBytes } + ModelSortOrder.SIZE_DESC -> _availableModels.value.sortedByDescending { it.sizeInBytes } + ModelSortOrder.LAST_USED -> _availableModels.value.sortedByDescending { it.lastUsed ?: 0 } + } + _availableModels.value = sorted + } + + fun setSortOrder(order: ModelSortOrder) { + _sortOrder.value = order + } + + fun viewModelDetails(modelId: String) { + // TODO-han.yin: Stub for now. Would navigate to model details screen or show dialog + } + + fun deleteModel(modelId: String) { + // Remove model from list + _availableModels.value = _availableModels.value.filter { it.id != modelId } + + viewModelScope.launch { + // TODO-han.yin: Stub for now this would delete from storage + modelRepository.deleteModel(modelId) + updateStorageMetrics() + } + } + + fun deleteModels(models: Map) { + val modelIds = models.keys + _availableModels.value = _availableModels.value.filter { !modelIds.contains(it.id) } + + viewModelScope.launch { + modelRepository.deleteModels(modelIds) + updateStorageMetrics() + } + } + + fun importLocalModel() { + // TODO-han.yin: Stub for now. Would open file picker and import model + } + + private fun updateStorageMetrics() { + // Recalculate storage metrics after model changes + // TODO-han.yin: Stub for now. Would query actual storage + val totalSize = _availableModels.value.sumOf { it.sizeInBytes } + _storageMetrics.value = StorageMetrics( + (totalSize / 1_000_000_000.0).toFloat(), + 32.0f + ) + } +} + +enum class ModelSortOrder { + NAME_ASC, + NAME_DESC, + SIZE_ASC, + SIZE_DESC, + LAST_USED +} + +