Skip to content

Commit

Permalink
Merge pull request #14177 from nextcloud/adopt-new-assistant-api-changes
Browse files Browse the repository at this point in the history
Add Backward Compatibility for Assistant API v1
  • Loading branch information
tobiasKaminsky authored Dec 16, 2024
2 parents 9f7370f + defdb92 commit 506fd49
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ package com.nextcloud.client.assistant

import com.nextcloud.client.assistant.repository.AssistantRepository
import com.owncloud.android.AbstractOnServerIT
import com.owncloud.android.lib.resources.assistant.model.TaskTypeData
import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData
import com.owncloud.android.lib.resources.status.NextcloudVersion
import org.junit.Assert.assertTrue
import org.junit.Before
Expand All @@ -22,7 +22,7 @@ class AssistantRepositoryTests : AbstractOnServerIT() {

@Before
fun setup() {
sut = AssistantRepository(nextcloudClient)
sut = AssistantRepository(nextcloudClient, capability)
}

@Test
Expand All @@ -34,10 +34,7 @@ class AssistantRepositoryTests : AbstractOnServerIT() {
}

val result = sut?.getTaskTypes()
assertTrue(result?.isSuccess == true)

val taskTypes = result?.resultData
assertTrue(taskTypes?.isNotEmpty() == true)
assertTrue(result?.isNotEmpty() == true)
}

@Test
Expand All @@ -49,10 +46,7 @@ class AssistantRepositoryTests : AbstractOnServerIT() {
}

val result = sut?.getTaskList("assistant")
assertTrue(result?.isSuccess == true)

val taskList = result?.resultData?.tasks
assertTrue(taskList?.isEmpty() == true || (taskList?.size ?: 0) > 0)
assertTrue(result?.isEmpty() == true || (result?.size ?: 0) > 0)
}

@Test
Expand Down Expand Up @@ -87,13 +81,11 @@ class AssistantRepositoryTests : AbstractOnServerIT() {

sleep(120)

val resultOfTaskList = sut?.getTaskList("assistant")
assertTrue(resultOfTaskList?.isSuccess == true)
val taskList = sut?.getTaskList("assistant")
assertTrue(taskList != null)

sleep(120)

val taskList = resultOfTaskList?.resultData?.tasks

assert((taskList?.size ?: 0) > 0)

val result = sut?.deleteTask(taskList!!.first().id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import com.nextcloud.client.assistant.model.ScreenOverlayState
import com.nextcloud.client.assistant.model.ScreenState
import com.nextcloud.client.assistant.repository.AssistantRepositoryType
import com.owncloud.android.R
import com.owncloud.android.lib.resources.assistant.model.Task
import com.owncloud.android.lib.resources.assistant.model.TaskTypeData
import com.owncloud.android.lib.resources.assistant.v2.model.Task
import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -80,16 +80,16 @@ class AssistantViewModel(
viewModelScope.launch(Dispatchers.IO) {
val taskTypesResult = repository.getTaskTypes()

if (taskTypesResult.isSuccess) {
val result = taskTypesResult.resultData
_taskTypes.update {
result
}

selectTaskType(result.first())
} else {
if (taskTypesResult.isNullOrEmpty()) {
updateSnackbarMessage(R.string.assistant_screen_task_types_error_state_message)
return@launch
}

_taskTypes.update {
taskTypesResult
}

selectTaskType(taskTypesResult.first())
}
}

Expand All @@ -101,8 +101,8 @@ class AssistantViewModel(

val taskType = _selectedTaskType.value?.id ?: return@launch
val result = repository.getTaskList(taskType)
if (result.isSuccess) {
taskList = result.resultData.tasks.filter { it.appId == "assistant" }
if (result != null) {
taskList = result
_filteredTaskList.update {
taskList?.sortedByDescending { task ->
task.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,17 @@ import com.nextcloud.ui.composeActivity.ComposeActivity
import com.nextcloud.ui.composeComponents.alertDialog.SimpleAlertDialog
import com.nextcloud.ui.composeComponents.bottomSheet.MoreActionsBottomSheet
import com.owncloud.android.R
import com.owncloud.android.lib.resources.assistant.model.Task
import com.owncloud.android.lib.resources.assistant.model.TaskTypeData
import com.owncloud.android.lib.resources.assistant.v2.model.Task
import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData
import com.owncloud.android.lib.resources.status.OCCapability
import com.owncloud.android.utils.DisplayUtils
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@Suppress("LongMethod")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AssistantScreen(viewModel: AssistantViewModel, activity: Activity) {
fun AssistantScreen(viewModel: AssistantViewModel, capability: OCCapability, activity: Activity) {
val messageId by viewModel.snackbarMessageId.collectAsState()
val screenOverlayState by viewModel.screenOverlayState.collectAsState()

Expand All @@ -81,7 +82,7 @@ fun AssistantScreen(viewModel: AssistantViewModel, activity: Activity) {
}
)
) {
ShowScreenState(screenState, selectedTaskType, taskTypes, viewModel, filteredTaskList)
ShowScreenState(screenState, selectedTaskType, taskTypes, viewModel, filteredTaskList, capability)

ShowLinearProgressIndicator(screenState, pullRefreshState)

Expand All @@ -104,7 +105,8 @@ private fun ShowScreenState(
selectedTaskType: TaskTypeData?,
taskTypes: List<TaskTypeData>?,
viewModel: AssistantViewModel,
filteredTaskList: List<Task>?
filteredTaskList: List<Task>?,
capability: OCCapability
) {
when (screenState) {
ScreenState.Refreshing -> {
Expand All @@ -120,7 +122,8 @@ private fun ShowScreenState(
filteredTaskList ?: listOf(),
taskTypes,
selectedTaskType,
viewModel
viewModel,
capability
)
}

Expand Down Expand Up @@ -223,7 +226,8 @@ private fun AssistantContent(
taskList: List<Task>,
taskTypes: List<TaskTypeData>?,
selectedTaskType: TaskTypeData?,
viewModel: AssistantViewModel
viewModel: AssistantViewModel,
capability: OCCapability
) {
Column(modifier = Modifier.fillMaxSize()) {
taskTypes?.let {
Expand All @@ -240,6 +244,7 @@ private fun AssistantContent(
items(taskList) { task ->
TaskView(
task,
capability,
showTaskActions = {
val newState = ScreenOverlayState.TaskActions(task)
viewModel.updateScreenState(newState)
Expand Down Expand Up @@ -279,6 +284,7 @@ private fun EmptyTaskList(
}
}

@Suppress("MagicNumber")
@Composable
@Preview
private fun AssistantScreenPreview() {
Expand All @@ -287,12 +293,16 @@ private fun AssistantScreenPreview() {
content = {
AssistantScreen(
viewModel = AssistantViewModel(repository = mockRepository),
activity = ComposeActivity()
activity = ComposeActivity(),
capability = OCCapability().apply {
versionMayor = 30
}
)
}
)
}

@Suppress("MagicNumber")
@Composable
@Preview
private fun AssistantEmptyScreenPreview() {
Expand All @@ -301,7 +311,10 @@ private fun AssistantEmptyScreenPreview() {
content = {
AssistantScreen(
viewModel = AssistantViewModel(repository = mockRepository),
activity = ComposeActivity()
activity = ComposeActivity(),
capability = OCCapability().apply {
versionMayor = 30
}
)
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import android.content.Context
import com.nextcloud.utils.date.DateFormatPattern
import com.nextcloud.utils.date.DateFormatter
import com.owncloud.android.R
import com.owncloud.android.lib.resources.assistant.model.Task
import com.owncloud.android.lib.resources.assistant.v2.model.Task
import com.owncloud.android.lib.resources.status.NextcloudVersion
import com.owncloud.android.lib.resources.status.OCCapability
import java.util.concurrent.TimeUnit

fun Task.getInputAndOutput(): String {
Expand All @@ -37,8 +39,38 @@ fun Task.getInputTitle(): String {
}
}

@Suppress("MagicNumber")
fun Task.getStatusIcon(): Int {
fun Task.getStatusIcon(capability: OCCapability): Int {
return if (capability.version.isNewerOrEqual(NextcloudVersion.nextcloud_30)) {
getStatusIconV2()
} else {
getStatusIconV1()
}
}

private fun Task.getStatusIconV1(): Int {
return when (status) {
"0" -> {
R.drawable.ic_unknown
}
"1" -> {
R.drawable.ic_clock
}
"2" -> {
R.drawable.ic_modification_desc
}
"3" -> {
R.drawable.ic_check_circle_outline
}
"4" -> {
R.drawable.image_fail
}
else -> {
R.drawable.ic_unknown
}
}
}

private fun Task.getStatusIconV2(): Int {
return when (status) {
"STATUS_UNKNOWN" -> {
R.drawable.ic_unknown
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import com.nextcloud.client.assistant.extensions.getInput
import com.nextcloud.client.assistant.extensions.getInputAndOutput
import com.nextcloud.utils.extensions.showShareIntent
import com.owncloud.android.R
import com.owncloud.android.lib.resources.assistant.model.Task
import com.owncloud.android.lib.resources.assistant.model.TaskTypeData
import com.owncloud.android.lib.resources.assistant.v2.model.Task
import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData
import com.owncloud.android.utils.ClipboardUtil

sealed class ScreenOverlayState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,64 @@ package com.nextcloud.client.assistant.repository

import com.nextcloud.utils.extensions.getRandomString
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.assistant.model.Task
import com.owncloud.android.lib.resources.assistant.model.TaskInput
import com.owncloud.android.lib.resources.assistant.model.TaskList
import com.owncloud.android.lib.resources.assistant.model.TaskOutput
import com.owncloud.android.lib.resources.assistant.model.TaskTypeData
import com.owncloud.android.lib.resources.assistant.v2.model.Task
import com.owncloud.android.lib.resources.assistant.v2.model.TaskInput
import com.owncloud.android.lib.resources.assistant.v2.model.TaskInputShape
import com.owncloud.android.lib.resources.assistant.v2.model.TaskOutput
import com.owncloud.android.lib.resources.assistant.v2.model.TaskOutputShape
import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData

@Suppress("MagicNumber")
class AssistantMockRepository(private val giveEmptyTasks: Boolean = false) : AssistantRepositoryType {
override fun getTaskTypes(): RemoteOperationResult<List<TaskTypeData>> {
return RemoteOperationResult<List<TaskTypeData>>(RemoteOperationResult.ResultCode.OK).apply {
resultData = null
}
override fun getTaskTypes(): List<TaskTypeData> {
return listOf(
TaskTypeData(
"core:text2text",
"Free text to text prompt",
"Runs an arbitrary prompt through a language model that returns a reply",
listOf(
TaskInputShape(
"Prompt",
"Describe a task that you want the assistant to do or ask a question",
"Text"
)
),
listOf(
TaskOutputShape(
"Generated reply",
"The generated text from the assistant",
"Text"
)
)
)
)
}

override fun createTask(input: String, taskType: TaskTypeData): RemoteOperationResult<Void> {
return RemoteOperationResult<Void>(RemoteOperationResult.ResultCode.OK)
}

override fun getTaskList(taskType: String): RemoteOperationResult<TaskList> {
val taskList = if (giveEmptyTasks) {
TaskList(listOf())
override fun getTaskList(taskType: String): List<Task> {
return if (giveEmptyTasks) {
listOf()
} else {
TaskList(
listOf(
Task(
1,
"FreePrompt",
null,
"12",
"",
TaskInput("Give me some long text 1"),
TaskOutput("Lorem ipsum".getRandomString(100)),
1707692337,
1707692337,
1707692337,
1707692337,
1707692337
)
listOf(
Task(
1,
"FreePrompt",
null,
"12",
"",
TaskInput("Give me some long text 1"),
TaskOutput("Lorem ipsum".getRandomString(100)),
1707692337,
1707692337,
1707692337,
1707692337,
1707692337
)
)
}

return RemoteOperationResult<TaskList>(RemoteOperationResult.ResultCode.OK).apply {
resultData = taskList
}
}

override fun deleteTask(id: Long): RemoteOperationResult<Void> {
Expand Down
Loading

0 comments on commit 506fd49

Please sign in to comment.