Skip to content

Commit

Permalink
feat: Add translation capabilities to mail
Browse files Browse the repository at this point in the history
Signed-off-by: Grigory Vodyanov <[email protected]>
  • Loading branch information
GVodyanov authored and hamza221 committed Jan 9, 2025
1 parent e9c7893 commit 638ecc5
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 7 deletions.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The rating depends on the installed text processing backend. See [the rating ove
Learn more about the Nextcloud Ethical AI Rating [in our blog](https://nextcloud.com/blog/nextcloud-ethical-ai-rating/).
]]></description>
<version>4.2.0-alpha.1</version>
<version>4.2.0-alpha.2</version>
<licence>agpl</licence>
<author homepage="https://github.com/ChristophWurst">Christoph Wurst</author>
<author homepage="https://github.com/GretaD">GretaD</author>
Expand Down
5 changes: 5 additions & 0 deletions lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ public function index(): TemplateResponse {
$this->aiIntegrationsService->isLlmProcessingEnabled() && $this->aiIntegrationsService->isLlmAvailable(SummaryTaskType::class)
);

$this->initialStateService->provideInitialState(
'llm_translation_enabled',
$this->aiIntegrationsService->isTaskAvailable('core:text2text:translate')
);

$this->initialStateService->provideInitialState(
'llm_freeprompt_available',
$this->aiIntegrationsService->isLlmProcessingEnabled() && $this->aiIntegrationsService->isLlmAvailable(FreePromptTaskType::class)
Expand Down
7 changes: 6 additions & 1 deletion lib/Service/AiIntegrations/AiIntegrationsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public function summarizeMessages(Account $account, array $messages): void {
$this->logger->info('No text summary provider available');
return;
}

$client = $this->clientFactory->getClient($account);
try {
foreach ($messages as $entry) {
Expand Down Expand Up @@ -356,6 +356,11 @@ public function isLlmAvailable(string $taskType): bool {
return in_array($taskType, $manager->getAvailableTaskTypes(), true);
}

public function isTaskAvailable(string $taskName): bool {
$availableTasks = $this->taskProcessingManager->getAvailableTaskTypes();
return array_key_exists($taskName, $availableTasks);

Check warning on line 361 in lib/Service/AiIntegrations/AiIntegrationsService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/AiIntegrations/AiIntegrationsService.php#L359-L361

Added lines #L359 - L361 were not covered by tests
}

/**
* Whether the llm_processing admin setting is enabled globally on this instance.
*/
Expand Down
4 changes: 2 additions & 2 deletions src/components/Envelope.vue
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,13 @@
</template>
</NcActionInput>

<ActionButton :aria-label="t('spreed', 'Set custom snooze')"
<ActionButton :aria-label="t('mail', 'Set custom snooze')"
close-after-click
@click.stop="setCustomSnooze(customSnoozeDateTime)">
<template #icon>
<CheckIcon :size="16" />
</template>
{{ t('spreed', 'Set custom snooze') }}
{{ t('mail', 'Set custom snooze') }}
</ActionButton>
</template>
<template v-if="moreActionsOpen">
Expand Down
17 changes: 17 additions & 0 deletions src/components/MenuEnvelope.vue
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@
</template>
{{ t('mail', 'Unsnooze') }}
</ActionButton>
<ActionButton v-if="isTranslationEnabled ?? false"
:close-after-click="true"
@click.prevent="$emit('open-translation-modal')">
<template #icon>
<TranslationIcon :title="t('mail', 'Translate')"
:size="16" />
</template>
{{ t('mail', 'Translate') }}
</ActionButton>
<ActionButton :close-after-click="false"
@click="localMoreActionsOpen=true">
<template #icon>
Expand Down Expand Up @@ -214,6 +223,7 @@ import ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'
import DotsHorizontalIcon from 'vue-material-design-icons/DotsHorizontal.vue'
import DownloadIcon from 'vue-material-design-icons/Download.vue'
import PrinterIcon from 'vue-material-design-icons/Printer.vue'
import TranslationIcon from 'vue-material-design-icons/Translate.vue'
import { mailboxHasRights } from '../util/acl.js'
import { generateUrl } from '@nextcloud/router'
import InformationIcon from 'vue-material-design-icons/Information.vue'
Expand Down Expand Up @@ -247,6 +257,7 @@ export default {
ChevronLeft,
CheckIcon,
DotsHorizontalIcon,
TranslationIcon,
DownloadIcon,
InformationIcon,
OpenInNewIcon,
Expand Down Expand Up @@ -283,6 +294,11 @@ export default {
type: Boolean,
default: true,
},
isTranslationAvailable: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
Expand All @@ -296,6 +312,7 @@ export default {
computed: {
...mapGetters([
'isSnoozeDisabled',
'isTranslationEnabled',
]),
account() {
const accountId = this.envelope.accountId ?? this.mailbox.accountId
Expand Down
29 changes: 28 additions & 1 deletion src/components/ThreadEnvelope.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@
@open-tag-modal="onOpenTagModal"
@open-move-modal="onOpenMoveModal"
@open-event-modal="onOpenEventModal"
@open-task-modal="onOpenTaskModal" />
@open-task-modal="onOpenTaskModal"
@open-translation-modal="onOpenTranslationModal" />
</NcActions>
<NcModal v-if="showSourceModal" class="source-modal" @close="onCloseSourceModal">
<div class="source-modal-content">
Expand All @@ -217,6 +218,10 @@
:account="account"
:envelopes="[envelope]"
@close="onCloseTagModal" />
<TranslationModal v-if="showTranslationModal"
:rich-parameters="{}"
:message="plainTextBody"
@close="onCloseTranslationModal" />
</template>
</div>
</div>
Expand Down Expand Up @@ -299,6 +304,7 @@ import TagModal from './TagModal.vue'
import MoveModal from './MoveModal.vue'
import TaskModal from './TaskModal.vue'
import EventModal from './EventModal.vue'
import TranslationModal from './TranslationModal.vue'
import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
Expand All @@ -307,6 +313,7 @@ import { mapStores } from 'pinia'
import moment from '@nextcloud/moment'
import { translateTagDisplayName } from '../util/tag.js'
import { FOLLOW_UP_TAG_LABEL } from '../store/constants.js'
import { Text, toPlain } from '../util/text.js'

// Ternary loading state
const LOADING_DONE = 0
Expand All @@ -321,6 +328,7 @@ export default {
TaskModal,
MoveModal,
TagModal,
TranslationModal,
ConfirmModal,
Avatar,
NcActionButton,
Expand Down Expand Up @@ -398,6 +406,8 @@ export default {
showEventModal: false,
showTaskModal: false,
showTagModal: false,
showTranslationModal: false,
plainTextBody: '',
rawMessage: '', // Will hold the raw source of the message when requested
isInternal: true,
enabledSmartReply: loadState('mail', 'llm_freeprompt_available', false),
Expand Down Expand Up @@ -863,6 +873,23 @@ export default {
onCloseTagModal() {
this.showTagModal = false
},
onOpenTranslationModal() {
try {
if (this.message.hasHtmlBody) {
let text = new Text('html', this.message.body)
text = toPlain(text)
this.plainTextBody = text.value
} else {
this.plainTextBody = this.message.body
}
this.showTranslationModal = true
} catch (error) {
showError(t('mail', 'Please wait for the message to load'))
}
},
onCloseTranslationModal() {
this.showTranslationModal = false
},
async onShowSourceModal() {
if (this.rawMessage.length === 0) {
const resp = await axios.get(
Expand Down
Loading

0 comments on commit 638ecc5

Please sign in to comment.