diff --git a/lib/Controller/ChattyLLMController.php b/lib/Controller/ChattyLLMController.php index 8a6aac36..da36e99a 100644 --- a/lib/Controller/ChattyLLMController.php +++ b/lib/Controller/ChattyLLMController.php @@ -311,6 +311,7 @@ public function deleteSession(int $sessionId): JSONResponse { * * Get all chat sessions for the current user * + * @param bool|null $isAssignment Whether to get only the sessions for assignments (true) or not (false) defaults to false * @return JSONResponse, array{}>|JSONResponse * * 200: The session list has been obtained successfully @@ -318,9 +319,9 @@ public function deleteSession(int $sessionId): JSONResponse { */ #[NoAdminRequired] #[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT, tags: ['chat_api'])] - public function getSessions(): JSONResponse { + public function getSessions(?bool $isAssignment = false): JSONResponse { try { - $sessions = $this->chatService->getSessionsForUser($this->userId); + $sessions = $this->chatService->getSessionsForUser($this->userId, $isAssignment); /** @var list $serializedSessions */ $serializedSessions = array_map(static function ($session) { return $session->jsonSerialize(); @@ -380,6 +381,7 @@ public function newMessage( * @param int $sessionId The session ID * @param int $limit The max number of messages to return * @param int $cursor The index of the first result to return + * @param bool $hideUserMessages Whether to hide user messages from the response * @return JSONResponse, array{}>|JSONResponse * * 200: The message list has been successfully obtained @@ -388,9 +390,9 @@ public function newMessage( */ #[NoAdminRequired] #[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT, tags: ['chat_api'])] - public function getMessages(int $sessionId, int $limit = 20, int $cursor = 0): JSONResponse { + public function getMessages(int $sessionId, int $limit = 20, int $cursor = 0, bool $hideUserMessages = false): JSONResponse { try { - $messages = $this->chatService->getSessionMessages($this->userId, $sessionId, $limit, $cursor); + $messages = $this->chatService->getSessionMessages($this->userId, $sessionId, $limit, $cursor, $hideUserMessages); return new JSONResponse(array_map(static function (Message $message) { return $message->jsonSerialize(); }, $messages)); diff --git a/lib/Db/ChattyLLM/MessageMapper.php b/lib/Db/ChattyLLM/MessageMapper.php index a0c4c0ce..1c69fef6 100644 --- a/lib/Db/ChattyLLM/MessageMapper.php +++ b/lib/Db/ChattyLLM/MessageMapper.php @@ -80,10 +80,11 @@ public function getLastNonEmptyHumanMessage(int $sessionId): Message { * @param int $sessionId * @param int $cursor * @param int $limit + * @param bool $hideUserMessages * @return list * @throws \OCP\DB\Exception */ - public function getMessages(int $sessionId, int $cursor, int $limit): array { + public function getMessages(int $sessionId, int $cursor, int $limit, bool $hideUserMessages = false): array { $qb = $this->db->getQueryBuilder(); $qb->select(Message::$columns) ->from($this->getTableName()) @@ -91,6 +92,10 @@ public function getMessages(int $sessionId, int $cursor, int $limit): array { ->orderBy('id', 'DESC') ->setFirstResult($cursor); + if ($hideUserMessages) { + $qb->andWhere($qb->expr()->neq('role', $qb->createPositionalParameter(Message::ROLE_HUMAN, IQueryBuilder::PARAM_STR))); + } + if ($limit > 0) { $qb->setMaxResults($limit); } diff --git a/lib/Db/ChattyLLM/SessionMapper.php b/lib/Db/ChattyLLM/SessionMapper.php index babf812c..dfc6fe73 100644 --- a/lib/Db/ChattyLLM/SessionMapper.php +++ b/lib/Db/ChattyLLM/SessionMapper.php @@ -84,16 +84,23 @@ public function getUserSessionForAssignment(string $userId, int $assignmentId): /** * @param string $userId + * @param bool $isAssignment * @return list * @throws \OCP\DB\Exception */ - public function getUserSessions(string $userId): array { + public function getUserSessions(string $userId, bool $isAssignment): array { $qb = $this->db->getQueryBuilder(); $qb->select(Session::$columns) ->from($this->getTableName()) ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId, IQueryBuilder::PARAM_STR))) ->orderBy('timestamp', 'DESC'); + if ($isAssignment) { + $qb->andWhere($qb->expr()->isNotNull('assignment_id')); + } else { + $qb->andWhere($qb->expr()->isNull('assignment_id')); + } + return $this->findEntities($qb); } diff --git a/lib/Service/AssistantService.php b/lib/Service/AssistantService.php index cf0438e7..dd00054e 100644 --- a/lib/Service/AssistantService.php +++ b/lib/Service/AssistantService.php @@ -64,6 +64,7 @@ class AssistantService { private const TASK_TYPE_PRIORITIES = [ 'chatty-llm' => 1, + 'assignments' => 1, TextToText::ID => 2, 'context_chat:context_chat' => 3, 'legacy:TextProcessing:OCA\ContextChat\TextProcessing\ContextChatTaskType' => 3, @@ -287,6 +288,9 @@ private function getCategory(string $typeId): array { if (str_starts_with($typeId, 'chatty')) { $categoryId = 'chat'; $categoryName = $this->l10n->t('Chat with AI'); + } elseif (str_starts_with($typeId, 'assignments')) { + $categoryId = 'assignments'; + $categoryName = $this->l10n->t('Scheduled tasks'); } elseif (str_starts_with($typeId, 'context_chat')) { $categoryId = 'context'; $categoryName = $this->l10n->t('Context Chat'); @@ -435,6 +439,23 @@ public function getAvailableTaskTypes(): array { 'priority' => self::TASK_TYPE_PRIORITIES['chatty-llm'] ?? 1000, 'preferredProviderName' => $preferredProviderName, ]; + // add the chattyUI assignments virtual task type + $types[] = [ + 'id' => 'assignments', + 'name' => $this->l10n->t('Scheduled tasks'), + 'description' => $this->l10n->t('Scheduled tasks'), + 'category' => $this->getCategory('assignments'), + 'inputShape' => [], + 'inputShapeEnumValues' => [], + 'inputShapeDefaults' => [], + 'outputShape' => [], + 'optionalInputShape' => [], + 'optionalInputShapeEnumValues' => [], + 'optionalInputShapeDefaults' => [], + 'optionalOutputShape' => [], + 'priority' => self::TASK_TYPE_PRIORITIES['assignments'] ?? 1000, + 'preferredProviderName' => $preferredProviderName, + ]; // do not add the raw TextToTextChat type if (!self::DEBUG) { continue; diff --git a/lib/Service/ChatService.php b/lib/Service/ChatService.php index 7586c4b9..6ee6c7b7 100644 --- a/lib/Service/ChatService.php +++ b/lib/Service/ChatService.php @@ -157,12 +157,12 @@ public function deleteSession(?string $userId, int $sessionId): void { * @throws InternalException * @throws UnauthorizedException */ - public function getSessionsForUser(?string $userId): array { + public function getSessionsForUser(?string $userId, bool $isAssignment): array { if ($userId === null) { throw new UnauthorizedException($this->l10n->t('Unauthorized')); } try { - return $this->sessionMapper->getUserSessions($userId); + return $this->sessionMapper->getUserSessions($userId, $isAssignment); } catch (Exception $e) { throw new InternalException(previous: $e); } @@ -250,7 +250,7 @@ public function createMessage(?string $userId, int $sessionId, string $role, str * @throws NotFoundException * @throws UnauthorizedException */ - public function getSessionMessages(?string $userId, int $sessionId, int $limit = 20, int $cursor = 0): array { + public function getSessionMessages(?string $userId, int $sessionId, int $limit = 20, int $cursor = 0, bool $hideUserMessages = false): array { if ($userId === null) { throw new UnauthorizedException($this->l10n->t('Unauthorized')); } @@ -268,7 +268,7 @@ public function getSessionMessages(?string $userId, int $sessionId, int $limit = /** @var list $messages */ try { - $messages = $this->messageMapper->getMessages($sessionId, $cursor, $limit); + $messages = $this->messageMapper->getMessages($sessionId, $cursor, $limit, $hideUserMessages); } catch (Exception $e) { throw new InternalException(previous: $e); } diff --git a/openapi.json b/openapi.json index 7bd328db..4b8e988e 100644 --- a/openapi.json +++ b/openapi.json @@ -2896,6 +2896,16 @@ } ], "parameters": [ + { + "name": "isAssignment", + "in": "query", + "description": "Whether to get only the sessions for assignments (true) or not (false) defaults to false", + "schema": { + "type": "boolean", + "nullable": true, + "default": false + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -4041,6 +4051,15 @@ "default": 0 } }, + { + "name": "hideUserMessages", + "in": "query", + "description": "Whether to hide user messages from the response", + "schema": { + "type": "boolean", + "default": false + } + }, { "name": "OCS-APIRequest", "in": "header", diff --git a/package-lock.json b/package-lock.json index 4d4f9c7c..7e04b228 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "assistant", - "version": "3.2.0", + "version": "3.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "assistant", - "version": "3.2.0", + "version": "3.4.1", "license": "AGPL-3.0", "dependencies": { "@breezystack/lamejs": "^1.2.7", @@ -26,6 +26,7 @@ "@primeuix/themes": "^2.0.3", "extendable-media-recorder": "^9.2.11", "extendable-media-recorder-wav-encoder": "^7.0.129", + "ical.js": "^2.2.1", "moment": "^2.30.1", "primevue": "^4.5.4", "v-click-outside": "^3.2.0", @@ -3520,9 +3521,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3545,9 +3543,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3570,9 +3565,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3595,9 +3587,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3620,9 +3609,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3645,9 +3631,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3969,9 +3952,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3987,9 +3967,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4005,9 +3982,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4023,9 +3997,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4041,9 +4012,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4059,9 +4027,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4077,9 +4042,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4095,9 +4057,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4113,9 +4072,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4131,9 +4087,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4149,9 +4102,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4167,9 +4117,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -4185,9 +4132,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -4991,9 +4935,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5009,9 +4950,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5027,9 +4965,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5045,9 +4980,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5063,9 +4995,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5081,9 +5010,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5099,9 +5025,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -5117,9 +5040,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -9488,6 +9408,12 @@ "dev": true, "license": "MIT" }, + "node_modules/ical.js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ical.js/-/ical.js-2.2.1.tgz", + "integrity": "sha512-yK/UlPbEs316igb/tjRgbFA8ZV75rCsBJp/hWOatpyaPNlgw0dGDmU+FoicOcwX4xXkeXOkYiOmCqNPFpNPkQg==", + "license": "MPL-2.0" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", diff --git a/package.json b/package.json index e5fa2556..f32e691f 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@primeuix/themes": "^2.0.3", "extendable-media-recorder": "^9.2.11", "extendable-media-recorder-wav-encoder": "^7.0.129", + "ical.js": "^2.2.1", "moment": "^2.30.1", "primevue": "^4.5.4", "v-click-outside": "^3.2.0", diff --git a/src/components/AssistantTextProcessingForm.vue b/src/components/AssistantTextProcessingForm.vue index 7f35482b..48e0e42e 100644 --- a/src/components/AssistantTextProcessingForm.vue +++ b/src/components/AssistantTextProcessingForm.vue @@ -17,7 +17,10 @@ :options="sortedTaskTypes" @update:model-value="onTaskTypeUserChange" />
- +
@@ -516,6 +519,10 @@ export default { this.loadingTaskTypes = false }) }, + onOpenChatFromAssignment() { + this.mySelectedTaskTypeId = CHAT_TASK_TYPE_ID + this.onTaskTypeUserChange() + }, onTaskTypeUserChange() { this.$emit('new-task') diff --git a/src/components/ChattyLLM/ChattyLLMInputForm.vue b/src/components/ChattyLLM/ChattyLLMInputForm.vue index 7c11ef18..a498527b 100644 --- a/src/components/ChattyLLM/ChattyLLMInputForm.vue +++ b/src/components/ChattyLLM/ChattyLLMInputForm.vue @@ -1,12 +1,13 @@ + -->