diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/AssistantJson.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/AssistantJson.kt new file mode 100644 index 0000000000..89e0fd7c8c --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/AssistantJson.kt @@ -0,0 +1,16 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.assistant + +import kotlinx.serialization.json.Json + +internal val assistantRequestJson = + Json { + encodeDefaults = true + explicitNulls = false + } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/EmptyArrayAsObjectSerializer.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/EmptyArrayAsObjectSerializer.kt new file mode 100644 index 0000000000..0fa609b60f --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/EmptyArrayAsObjectSerializer.kt @@ -0,0 +1,21 @@ +/* + * Nextcloud Android Library + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: MIT + */ + +package com.owncloud.android.lib.resources.assistant + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonTransformingSerializer + +internal open class EmptyArrayAsObjectSerializer( + serializer: KSerializer +) : JsonTransformingSerializer(serializer) { + override fun transformDeserialize(element: JsonElement): JsonElement = + if (element is JsonArray && element.isEmpty()) JsonObject(emptyMap()) else element +} diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CheckGenerationRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CheckGenerationRemoteOperation.kt index 138daf9b9e..28fa990f50 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CheckGenerationRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CheckGenerationRemoteOperation.kt @@ -12,6 +12,7 @@ import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.assistant.chat.model.ChatMessage import org.apache.commons.httpclient.HttpStatus @@ -31,7 +32,7 @@ class CheckGenerationRemoteOperation( return try { if (status == HttpStatus.SC_OK) { val responseBody = getMethod.getResponseBodyAsString() - val jsonResponse = gson.fromJson(responseBody, ChatMessage::class.java) + val jsonResponse = ocsJson.decodeFromString(responseBody) val result = RemoteOperationResult(true, getMethod) result.resultData = jsonResponse diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CheckSessionRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CheckSessionRemoteOperation.kt index 98cedf3b7c..7b089c341d 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CheckSessionRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CheckSessionRemoteOperation.kt @@ -13,6 +13,7 @@ import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.assistant.chat.model.Session import org.apache.commons.httpclient.HttpStatus @@ -31,7 +32,7 @@ class CheckSessionRemoteOperation( return try { if (status == HttpStatus.SC_OK) { val responseBody = getMethod.getResponseBodyAsString() - val jsonResponse = gson.fromJson(responseBody, Session::class.java) + val jsonResponse = ocsJson.decodeFromString(responseBody) val result = RemoteOperationResult(true, getMethod) result.resultData = jsonResponse diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CreateConversationRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CreateConversationRemoteOperation.kt index 51818f16cd..e9fb6889f1 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CreateConversationRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CreateConversationRemoteOperation.kt @@ -8,13 +8,15 @@ package com.owncloud.android.lib.resources.assistant.chat -import com.google.gson.reflect.TypeToken import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.PutMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.assistant.chat.model.CreateConversation +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.toRequestBody import org.apache.commons.httpclient.HttpStatus @@ -25,13 +27,11 @@ class CreateConversationRemoteOperation( ) : RemoteOperation() { @Suppress("TooGenericExceptionCaught") override fun run(client: NextcloudClient): RemoteOperationResult { - val bodyMap = - hashMapOf( - "title" to title, - "timestamp" to timestamp - ) - - val json = gson.toJson(bodyMap) + val json = + buildJsonObject { + title?.let { put("title", it) } + put("timestamp", timestamp) + }.toString() val requestBody = json.toRequestBody("application/json".toMediaTypeOrNull()) val putMethod = PutMethod(client.baseUri.toString() + "$BASE_URL/new_session", true, requestBody) @@ -40,8 +40,7 @@ class CreateConversationRemoteOperation( return try { if (status == HttpStatus.SC_OK) { val responseBody = putMethod.getResponseBodyAsString() - val type = object : TypeToken() {}.type - val response: CreateConversation = gson.fromJson(responseBody, type) + val response = ocsJson.decodeFromString(responseBody) val result: RemoteOperationResult = RemoteOperationResult(true, putMethod) result.resultData = response result diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CreateMessageRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CreateMessageRemoteOperation.kt index 1bb98be677..75cac874fd 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CreateMessageRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/CreateMessageRemoteOperation.kt @@ -8,13 +8,14 @@ package com.owncloud.android.lib.resources.assistant.chat -import com.google.gson.reflect.TypeToken import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.PutMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.assistant.chat.model.ChatMessage +import com.owncloud.android.lib.resources.assistant.assistantRequestJson import com.owncloud.android.lib.resources.assistant.chat.model.ChatMessageRequest import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.toRequestBody @@ -25,7 +26,7 @@ class CreateMessageRemoteOperation( ) : RemoteOperation() { @Suppress("TooGenericExceptionCaught") override fun run(client: NextcloudClient): RemoteOperationResult { - val json = gson.toJson(messageRequest.bodyMap) + val json = assistantRequestJson.encodeToString(messageRequest) val requestBody = json.toRequestBody("application/json".toMediaTypeOrNull()) val putMethod = PutMethod(client.baseUri.toString() + "$BASE_URL/new_message", true, requestBody) @@ -34,8 +35,7 @@ class CreateMessageRemoteOperation( return try { if (status == HttpStatus.SC_OK) { val responseBody = putMethod.getResponseBodyAsString() - val type = object : TypeToken() {}.type - val response: ChatMessage = gson.fromJson(responseBody, type) + val response = ocsJson.decodeFromString(responseBody) val result: RemoteOperationResult = RemoteOperationResult(true, putMethod) result.resultData = response result diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GenerateSessionRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GenerateSessionRemoteOperation.kt index a06062f329..d4f125bfe4 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GenerateSessionRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GenerateSessionRemoteOperation.kt @@ -13,6 +13,7 @@ import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.assistant.chat.model.SessionTask import org.apache.commons.httpclient.HttpStatus @@ -28,7 +29,7 @@ class GenerateSessionRemoteOperation( return try { if (status == HttpStatus.SC_OK) { val responseBody = getMethod.getResponseBodyAsString() - val jsonResponse = gson.fromJson(responseBody, SessionTask::class.java) + val jsonResponse = ocsJson.decodeFromString(responseBody) val result = RemoteOperationResult(true, getMethod) result.resultData = jsonResponse diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GetConversationListRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GetConversationListRemoteOperation.kt index a2f9db9d4a..aaaf179272 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GetConversationListRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GetConversationListRemoteOperation.kt @@ -8,12 +8,12 @@ package com.owncloud.android.lib.resources.assistant.chat -import com.google.gson.reflect.TypeToken import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.assistant.chat.model.Conversation import org.apache.commons.httpclient.HttpStatus @@ -26,8 +26,7 @@ class GetConversationListRemoteOperation : RemoteOperation>() return try { if (status == HttpStatus.SC_OK) { val responseBody = getMethod.getResponseBodyAsString() - val type = object : TypeToken>() {}.type - val conversationList: List = gson.fromJson(responseBody, type) + val conversationList = ocsJson.decodeFromString>(responseBody) val result = RemoteOperationResult>(true, getMethod) result.resultData = conversationList diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GetMessagesRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GetMessagesRemoteOperation.kt index ff26c18d36..d559361156 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GetMessagesRemoteOperation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/GetMessagesRemoteOperation.kt @@ -8,12 +8,12 @@ package com.owncloud.android.lib.resources.assistant.chat -import com.google.gson.reflect.TypeToken import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.assistant.chat.model.ChatMessage import org.apache.commons.httpclient.HttpStatus @@ -32,8 +32,7 @@ class GetMessagesRemoteOperation( return try { if (status == HttpStatus.SC_OK) { val responseBody = getMethod.getResponseBodyAsString() - val type = object : TypeToken>() {}.type - val response: List = gson.fromJson(responseBody, type) + val response = ocsJson.decodeFromString>(responseBody) val result: RemoteOperationResult> = RemoteOperationResult(true, getMethod) result.resultData = response result diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/ChatMessage.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/ChatMessage.kt index 618eb95a68..e137d43462 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/ChatMessage.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/ChatMessage.kt @@ -8,17 +8,20 @@ package com.owncloud.android.lib.resources.assistant.chat.model -import com.google.gson.annotations.SerializedName +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement +@Serializable data class ChatMessage( val id: Long, - @SerializedName("session_id") + @SerialName("session_id") val sessionId: Long, val role: String, val content: String, val timestamp: Long, - @SerializedName("ocp_task_id") - val ocpTaskId: Any?, - val sources: String, - val attachments: List + @SerialName("ocp_task_id") + val ocpTaskId: Long? = null, + val sources: String? = null, + val attachments: List = emptyList() ) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/ChatMessageRequest.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/ChatMessageRequest.kt index a6f3792e8f..00fa073a64 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/ChatMessageRequest.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/ChatMessageRequest.kt @@ -8,6 +8,9 @@ package com.owncloud.android.lib.resources.assistant.chat.model +import kotlinx.serialization.Serializable + +@Serializable data class ChatMessageRequest( val sessionId: String, val role: String, @@ -15,14 +18,4 @@ data class ChatMessageRequest( val timestamp: Long, val attachments: List? = null, val firstHumanMessage: Boolean = false -) { - val bodyMap = - hashMapOf( - "sessionId" to sessionId, - "role" to role, - "content" to content, - "timestamp" to timestamp, - "firstHumanMessage" to firstHumanMessage, - "attachments" to attachments - ) -} +) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/Conversation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/Conversation.kt index a2c394869f..6734a4b9ad 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/Conversation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/Conversation.kt @@ -8,7 +8,9 @@ package com.owncloud.android.lib.resources.assistant.chat.model -import com.google.gson.annotations.SerializedName +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement import java.time.ZoneId import java.time.format.DateTimeFormatter import java.util.Locale @@ -16,16 +18,17 @@ import kotlin.time.ExperimentalTime import kotlin.time.Instant import kotlin.time.toJavaInstant +@Serializable data class Conversation( val id: Long, - @SerializedName("user_id") + @SerialName("user_id") val userId: String, - val title: String?, + val title: String? = null, val timestamp: Long, - @SerializedName("agency_conversation_token") - val agencyConversationToken: String, - @SerializedName("agency_pending_actions") - val agencyPendingActions: Any? + @SerialName("agency_conversation_token") + val agencyConversationToken: String? = null, + @SerialName("agency_pending_actions") + val agencyPendingActions: JsonElement? = null ) { companion object { private const val TITLE_PRESENTATION_TIME_PATTERN = "MMMM dd, yyyy HH:mm" diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/CreateConversation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/CreateConversation.kt index a05d6094f1..7f04237d80 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/CreateConversation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/CreateConversation.kt @@ -8,6 +8,9 @@ package com.owncloud.android.lib.resources.assistant.chat.model +import kotlinx.serialization.Serializable + +@Serializable data class CreateConversation( val session: Conversation ) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/Session.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/Session.kt index e5b1048618..c3c3610751 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/Session.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/chat/model/Session.kt @@ -8,14 +8,18 @@ package com.owncloud.android.lib.resources.assistant.chat.model +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement + +@Serializable data class Session( - val messageTaskId: Int?, - val titleTaskId: Int?, - val sessionTitle: String, - val sessionAgencyPendingActions: Any?, - val taskId: Long + val messageTaskId: Long? = null, + val titleTaskId: Long? = null, + val sessionTitle: String? = null, + val sessionAgencyPendingActions: JsonElement? = null ) +@Serializable data class SessionTask( val taskId: Long ) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/CreateTaskRemoteOperationV1.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/CreateTaskRemoteOperationV1.kt index 09dbae62bf..228696a421 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/CreateTaskRemoteOperationV1.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/CreateTaskRemoteOperationV1.kt @@ -12,6 +12,8 @@ import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.PostMethod import com.owncloud.android.lib.common.operations.RemoteOperation import com.owncloud.android.lib.common.operations.RemoteOperationResult +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.toRequestBody import org.apache.commons.httpclient.HttpStatus @@ -21,15 +23,13 @@ class CreateTaskRemoteOperationV1( private val type: String ) : RemoteOperation() { override fun run(client: NextcloudClient): RemoteOperationResult { - val requestBody = - hashMapOf( - "input" to input, - "type" to type, - "appId" to "assistant", - "identifier" to "" - ) - - val json = gson.toJson(requestBody) + val json = + buildJsonObject { + put("input", input) + put("type", type) + put("appId", "assistant") + put("identifier", "") + }.toString() val request = json.toRequestBody("application/json".toMediaTypeOrNull()) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/GetTaskListRemoteOperationV1.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/GetTaskListRemoteOperationV1.kt index b865e2d876..d401b55477 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/GetTaskListRemoteOperationV1.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/GetTaskListRemoteOperationV1.kt @@ -8,12 +8,12 @@ package com.owncloud.android.lib.resources.assistant.v1 -import com.google.gson.reflect.TypeToken import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.lib.ocs.ServerResponse +import com.owncloud.android.lib.ocs.OcsKotlinResponse +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.OCSRemoteOperation import com.owncloud.android.lib.resources.assistant.v1.model.TaskList import org.apache.commons.httpclient.HttpStatus @@ -30,11 +30,11 @@ class GetTaskListRemoteOperationV1( GetMethod(client.baseUri.toString() + DIRECT_ENDPOINT + appId + JSON_FORMAT, true) val status = client.execute(getMethod) if (status == HttpStatus.SC_OK) { - val taskTypes: TaskList? = - getServerResponse( - getMethod, - object : TypeToken>() {} - )?.ocs?.data + val taskTypes = + ocsJson + .decodeFromString>(getMethod.getResponseBodyAsString()) + .ocs + .data result = RemoteOperationResult(true, getMethod) result.setResultData(taskTypes) } else { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/GetTaskTypesRemoteOperationV1.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/GetTaskTypesRemoteOperationV1.kt index 7047022e22..ae4b016c3b 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/GetTaskTypesRemoteOperationV1.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/GetTaskTypesRemoteOperationV1.kt @@ -8,12 +8,12 @@ package com.owncloud.android.lib.resources.assistant.v1 -import com.google.gson.reflect.TypeToken import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.lib.ocs.ServerResponse +import com.owncloud.android.lib.ocs.OcsKotlinResponse +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.OCSRemoteOperation import com.owncloud.android.lib.resources.assistant.v1.model.TaskTypes import org.apache.commons.httpclient.HttpStatus @@ -28,11 +28,11 @@ class GetTaskTypesRemoteOperationV1 : OCSRemoteOperation() { GetMethod(client.baseUri.toString() + DIRECT_ENDPOINT + JSON_FORMAT, true) val status = client.execute(getMethod) if (status == HttpStatus.SC_OK) { - val taskTypes: TaskTypes? = - getServerResponse( - getMethod, - object : TypeToken>() {} - )?.ocs?.data + val taskTypes = + ocsJson + .decodeFromString>(getMethod.getResponseBodyAsString()) + .ocs + .data result = RemoteOperationResult(true, getMethod) result.setResultData(taskTypes) } else { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/model/TaskList.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/model/TaskList.kt index ef19a21036..16fd0b8383 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/model/TaskList.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/model/TaskList.kt @@ -8,20 +8,24 @@ package com.owncloud.android.lib.resources.assistant.v1.model +import kotlinx.serialization.Serializable + +@Serializable data class TaskList( var tasks: List ) +@Serializable data class Task( val id: Long, - val type: String?, - val status: Long?, - val userId: String?, - val appId: String?, - val input: String?, - val output: String?, - val identifier: String?, - val completionExpectedAt: String? = null + val type: String? = null, + val status: Long? = null, + val userId: String? = null, + val appId: String? = null, + val input: String? = null, + val output: String? = null, + val identifier: String? = null, + val completionExpectedAt: Long? = null ) fun TaskList.toV2(): com.owncloud.android.lib.resources.assistant.v2.model.TaskList = @@ -44,7 +48,7 @@ fun TaskList.toV2(): com.owncloud.android.lib.resources.assistant.v2.model.TaskL com.owncloud.android.lib.resources.assistant.v2.model .TaskOutput(output = it) }, - completionExpectedAt = task.completionExpectedAt?.toIntOrNull(), + completionExpectedAt = task.completionExpectedAt?.toInt(), progress = null, lastUpdated = null, scheduledAt = null, diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/model/TaskTypes.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/model/TaskTypes.kt index 9f2dedf851..0d514af576 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/model/TaskTypes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v1/model/TaskTypes.kt @@ -9,15 +9,18 @@ package com.owncloud.android.lib.resources.assistant.v1.model import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData +import kotlinx.serialization.Serializable +@Serializable data class TaskTypes( var types: List ) +@Serializable data class TaskType( - val id: String?, + val id: String? = null, val name: String, - val description: String? + val description: String? = null ) fun TaskTypes.toV2(): List = diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskListRemoteOperationV2.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskListRemoteOperationV2.kt index c72ff9ed37..2d7cae32c3 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskListRemoteOperationV2.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskListRemoteOperationV2.kt @@ -8,12 +8,12 @@ package com.owncloud.android.lib.resources.assistant.v2 -import com.google.gson.reflect.TypeToken import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.lib.ocs.ServerResponse +import com.owncloud.android.lib.ocs.OcsKotlinResponse +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.OCSRemoteOperation import com.owncloud.android.lib.resources.assistant.v2.model.TaskList import org.apache.commons.httpclient.HttpStatus @@ -30,11 +30,11 @@ class GetTaskListRemoteOperationV2( GetMethod(client.baseUri.toString() + DIRECT_ENDPOINT + taskType + "&format=json", true) val status = client.execute(getMethod) if (status == HttpStatus.SC_OK) { - val taskTypes: TaskList? = - getServerResponse( - getMethod, - object : TypeToken>() {} - )?.ocs?.data + val taskTypes = + ocsJson + .decodeFromString>(getMethod.getResponseBodyAsString()) + .ocs + .data result = RemoteOperationResult(true, getMethod) result.setResultData(taskTypes) } else { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskTypesRemoteOperationV2.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskTypesRemoteOperationV2.kt index 96a7372f21..75afd2bc23 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskTypesRemoteOperationV2.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskTypesRemoteOperationV2.kt @@ -8,15 +8,16 @@ package com.owncloud.android.lib.resources.assistant.v2 -import com.google.gson.reflect.TypeToken import com.nextcloud.common.NextcloudClient import com.nextcloud.operations.GetMethod import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.lib.ocs.ServerResponse +import com.owncloud.android.lib.ocs.OcsKotlinResponse +import com.owncloud.android.lib.ocs.ocsJson import com.owncloud.android.lib.resources.OCSRemoteOperation import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData -import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypes +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject import org.apache.commons.httpclient.HttpStatus /** @@ -58,21 +59,20 @@ class GetTaskTypesRemoteOperationV2 : OCSRemoteOperation>() { GetMethod(client.baseUri.toString() + DIRECT_ENDPOINT + JSON_FORMAT, true) val status = client.execute(getMethod) if (status == HttpStatus.SC_OK) { - val response = - getServerResponse( - getMethod, - object : TypeToken>() {} - ) + val response = getMethod.getResponseBodyAsString() + val types = + ocsJson + .decodeFromString>>(response) + .ocs + .data[TYPES_KEY] as? JsonObject val taskTypeList = - response - ?.ocs - ?.data - ?.types - ?.map { (key, value) -> value.copy(id = value.id ?: key) } - ?.filter { taskType -> + types + .orEmpty() + .mapNotNull { (key, value) -> decodeTaskType(key, value) } + .filter { taskType -> isSingleTextInputOutput(taskType) || taskType.isChat() || taskType.isTranslate() - }?.sortedByDescending { it.isChat() } + }.sortedByDescending { it.isChat() } result = RemoteOperationResult(true, getMethod) result.resultData = taskTypeList @@ -92,6 +92,19 @@ class GetTaskTypesRemoteOperationV2 : OCSRemoteOperation>() { return result } + @Suppress("TooGenericExceptionCaught") + private fun decodeTaskType( + key: String, + value: JsonElement + ): TaskTypeData? = + try { + val taskType = ocsJson.decodeFromJsonElement(TaskTypeData.serializer(), value) + taskType.copy(id = taskType.id ?: key) + } catch (e: Exception) { + Log_OC.w(TAG, "Skipping task type $key: ${e.message}") + null + } + private fun isSingleTextInputOutput(taskType: TaskTypeData): Boolean { val inputShape = taskType.inputShape val outputShape = taskType.outputShape @@ -110,5 +123,6 @@ class GetTaskTypesRemoteOperationV2 : OCSRemoteOperation>() { companion object { private val TAG = GetTaskTypesRemoteOperationV2::class.java.simpleName private const val DIRECT_ENDPOINT = "/ocs/v2.php/taskprocessing/tasktypes" + private const val TYPES_KEY = "types" } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskList.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskList.kt index 0660dcfe01..9d4f2a01da 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskList.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskList.kt @@ -8,31 +8,44 @@ package com.owncloud.android.lib.resources.assistant.v2.model +import com.owncloud.android.lib.resources.assistant.EmptyArrayAsObjectSerializer +import kotlinx.serialization.Serializable + +@Serializable data class TaskList( var tasks: List ) +@Serializable data class Task( val id: Long, - val type: String?, - val status: String?, - val userId: String?, - val appId: String?, - val input: TaskInput?, - val output: TaskOutput?, + val type: String? = null, + val status: String? = null, + val userId: String? = null, + val appId: String? = null, + @Serializable(with = TaskInputSerializer::class) + val input: TaskInput? = null, + @Serializable(with = TaskOutputSerializer::class) + val output: TaskOutput? = null, val completionExpectedAt: Int? = null, - var progress: Int? = null, + var progress: Double? = null, val lastUpdated: Int? = null, val scheduledAt: Int? = null, val endedAt: Int? = null ) { - fun isTranslate(): Boolean = (type == "core:text2text:translate") + fun isTranslate(): Boolean = (type == TaskTypeData.TRANSLATE_TASK_TYPE_ID) } +@Serializable data class TaskInput( var input: String? = null ) +@Serializable data class TaskOutput( var output: String? = null ) + +internal object TaskInputSerializer : EmptyArrayAsObjectSerializer(TaskInput.serializer()) + +internal object TaskOutputSerializer : EmptyArrayAsObjectSerializer(TaskOutput.serializer()) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskTypes.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskTypes.kt index 20340fe2f5..68088d15ee 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskTypes.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskTypes.kt @@ -8,30 +8,45 @@ package com.owncloud.android.lib.resources.assistant.v2.model +import com.owncloud.android.lib.resources.assistant.EmptyArrayAsObjectSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.builtins.MapSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.JsonObject + +@Serializable data class TaskTypes( val types: Map ) +@Serializable data class TaskTypeData( - val id: String?, + val id: String? = null, val name: String, - val description: String?, + val description: String? = null, + @Serializable(with = ShapeMapSerializer::class) val inputShape: Map, + @Serializable(with = ShapeMapSerializer::class) val outputShape: Map, - val optionalInputShapeDefaults: Map? = null, + @Serializable(with = ShapeDefaultsSerializer::class) + val optionalInputShapeDefaults: JsonObject? = null, + @Serializable(with = EnumValuesMapSerializer::class) val optionalInputShapeEnumValues: Map>? = null, + @Serializable(with = EnumValuesMapSerializer::class) val inputShapeEnumValues: Map>? = null, + @Serializable(with = EnumValuesMapSerializer::class) val outputShapeEnumValues: Map>? = null, + @Serializable(with = EnumValuesMapSerializer::class) val optionalOutputShapeEnumValues: Map>? = null ) { - private val chatTaskName = "Chat" - private val translateTaskName = "Translate" - - fun isChat(): Boolean = (name == chatTaskName) + fun isChat(): Boolean = (id == CHAT_TASK_TYPE_ID) - fun isTranslate(): Boolean = (name == translateTaskName) + fun isTranslate(): Boolean = (id == TRANSLATE_TASK_TYPE_ID) companion object { + const val CHAT_TASK_TYPE_ID = "core:text2text:chat" + const val TRANSLATE_TASK_TYPE_ID = "core:text2text:translate" private const val CONVERSATION_LIST_ID = "ConversationList" val conversationList = TaskTypeData( @@ -44,13 +59,26 @@ data class TaskTypeData( } } +@Serializable data class EnumValue( val name: String, val value: String ) +@Serializable data class Shape( val name: String, val description: String, val type: String ) + +internal object ShapeMapSerializer : + EmptyArrayAsObjectSerializer>(MapSerializer(String.serializer(), Shape.serializer())) + +internal object EnumValuesMapSerializer : + EmptyArrayAsObjectSerializer>>( + MapSerializer(String.serializer(), ListSerializer(EnumValue.serializer())) + ) + +internal object ShapeDefaultsSerializer : + EmptyArrayAsObjectSerializer(JsonObject.serializer()) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/Translation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/Translation.kt index ab0ad8c870..aff68dc0d7 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/Translation.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/Translation.kt @@ -10,6 +10,9 @@ package com.owncloud.android.lib.resources.assistant.v2.model import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.doubleOrNull data class TranslationLanguage( val name: String, @@ -51,7 +54,7 @@ fun TaskTypeData.toTranslationLanguages(): TranslationLanguages { } fun TaskTypeData.toTranslationModel(): TranslationModel? { - val model = optionalInputShapeDefaults?.get("model") as? String - val maxTokens = optionalInputShapeDefaults?.get("max_tokens") as? Double + val model = (optionalInputShapeDefaults?.get("model") as? JsonPrimitive)?.contentOrNull + val maxTokens = (optionalInputShapeDefaults?.get("max_tokens") as? JsonPrimitive)?.doubleOrNull return if (model != null && maxTokens != null) TranslationModel(model, maxTokens) else null }