diff options
| author | Hazelnoot <acomputerdog@gmail.com> | 2025-05-12 00:23:59 -0400 |
|---|---|---|
| committer | Hazelnoot <acomputerdog@gmail.com> | 2025-05-12 21:48:21 -0400 |
| commit | e7ee2cc398dd1bf9d04c30ebacff85c113714d15 (patch) | |
| tree | 36ccce4f4ed2c783a5492ca8c4354bba559fe47d | |
| parent | merge: Add "is from local bubble instance" role condition (!1011) (diff) | |
| download | sharkey-e7ee2cc398dd1bf9d04c30ebacff85c113714d15.tar.gz sharkey-e7ee2cc398dd1bf9d04c30ebacff85c113714d15.tar.bz2 sharkey-e7ee2cc398dd1bf9d04c30ebacff85c113714d15.zip | |
add configurable timeout for note translations
| -rw-r--r-- | locales/index.d.ts | 8 | ||||
| -rw-r--r-- | packages/backend/migration/1747023091463-add_meta_translationTimeout.js | 18 | ||||
| -rw-r--r-- | packages/backend/src/models/Meta.ts | 6 | ||||
| -rw-r--r-- | packages/backend/src/server/api/endpoints/admin/meta.ts | 5 | ||||
| -rw-r--r-- | packages/backend/src/server/api/endpoints/admin/update-meta.ts | 5 | ||||
| -rw-r--r-- | packages/backend/src/server/api/endpoints/notes/translate.ts | 2 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/external-services.vue | 20 | ||||
| -rw-r--r-- | packages/misskey-js/src/autogen/types.ts | 2 | ||||
| -rw-r--r-- | sharkey-locales/en-US.yml | 3 |
9 files changed, 66 insertions, 3 deletions
diff --git a/locales/index.d.ts b/locales/index.d.ts index 59637f0bcf..e40f67a495 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -13045,6 +13045,14 @@ export interface Locale extends ILocale { * Note: the bubble timeline is hidden by default, and must be enabled via roles. */ "bubbleTimelineMustBeEnabled": string; + /** + * Translation timeout + */ + "translationTimeoutLabel": string; + /** + * Timeout in milliseconds for translation API requests (default 5000) + */ + "translationTimeoutCaption": string; } declare const locales: { [lang: string]: Locale; diff --git a/packages/backend/migration/1747023091463-add_meta_translationTimeout.js b/packages/backend/migration/1747023091463-add_meta_translationTimeout.js new file mode 100644 index 0000000000..cf291f8d74 --- /dev/null +++ b/packages/backend/migration/1747023091463-add_meta_translationTimeout.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class AddMetaTranslationTimeout1747023091463 { + name = 'AddMetaTranslationTimeout1747023091463' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "translationTimeout" integer NOT NULL DEFAULT '5000'`); + await queryRunner.query(`COMMENT ON COLUMN "meta"."translationTimeout" IS 'Timeout in milliseconds for translation API requests'`); + } + + async down(queryRunner) { + await queryRunner.query(`COMMENT ON COLUMN "meta"."translationTimeout" IS 'Timeout in milliseconds for translation API requests'`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "translationTimeout"`); + } +} diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 78b3175458..5292480142 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -382,6 +382,12 @@ export class MiMeta { }) public swPrivateKey: string | null; + @Column('integer', { + default: 5000, + comment: 'Timeout in milliseconds for translation API requests', + }) + public translationTimeout: number; + @Column('varchar', { length: 1024, nullable: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index f059a3ed4d..13022f43a0 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -445,6 +445,10 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + translationTimeout: { + type: 'number', + optional: false, nullable: false, + }, deeplAuthKey: { type: 'string', optional: false, nullable: true, @@ -723,6 +727,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- objectStorageUseProxy: instance.objectStorageUseProxy, objectStorageSetPublicRead: instance.objectStorageSetPublicRead, objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle, + translationTimeout: instance.translationTimeout, deeplAuthKey: instance.deeplAuthKey, deeplIsPro: instance.deeplIsPro, deeplFreeMode: instance.deeplFreeMode, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index eb73c4b616..090681c134 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -103,6 +103,7 @@ export const paramDef = { type: 'string', }, }, + translationTimeout: { type: 'number' }, deeplAuthKey: { type: 'string', nullable: true }, deeplIsPro: { type: 'boolean' }, deeplFreeMode: { type: 'boolean' }, @@ -560,6 +561,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle; } + if (ps.translationTimeout !== undefined) { + set.translationTimeout = ps.translationTimeout; + } + if (ps.deeplAuthKey !== undefined) { if (ps.deeplAuthKey === '') { set.deeplAuthKey = null; diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index 39119bc206..843a4ef01c 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -116,6 +116,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- Accept: 'application/json, */*', }, body: params.toString(), + timeout: this.serverSettings.translationTimeout, }); if (this.serverSettings.deeplAuthKey) { const json = (await res.json()) as { @@ -165,6 +166,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- format: 'text', api_key: this.serverSettings.libreTranslateKey ?? '', }), + timeout: this.serverSettings.translationTimeout, }); const json = (await res.json()) as { diff --git a/packages/frontend/src/pages/admin/external-services.vue b/packages/frontend/src/pages/admin/external-services.vue index 3cfc51af00..ced74a5df4 100644 --- a/packages/frontend/src/pages/admin/external-services.vue +++ b/packages/frontend/src/pages/admin/external-services.vue @@ -8,6 +8,11 @@ SPDX-License-Identifier: AGPL-3.0-only <div class="_spacer" style="--MI_SPACER-w: 700px; --MI_SPACER-min: 16px; --MI_SPACER-max: 32px;"> <FormSuspense :p="init"> <div class="_gaps_m"> + <MkInput v-model="translationTimeout" type="number" debounce> + <template #label>{{ i18n.ts.translationTimeoutLabel }}</template> + <template #caption>{{ i18n.ts.translationTimeoutCaption }}</template> + </MkInput> + <MkFolder> <template #label>DeepL Translation</template> @@ -57,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref, computed } from 'vue'; +import { ref, computed, watch } from 'vue'; import MkInput from '@/components/MkInput.vue'; import MkButton from '@/components/MkButton.vue'; import MkSwitch from '@/components/MkSwitch.vue'; @@ -69,6 +74,7 @@ import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import MkFolder from '@/components/MkFolder.vue'; +const translationTimeout = ref(0); const deeplAuthKey = ref<string | null>(''); const deeplIsPro = ref<boolean>(false); const deeplFreeMode = ref<boolean>(false); @@ -78,12 +84,20 @@ const libreTranslateKey = ref<string | null>(''); async function init() { const meta = await misskeyApi('admin/meta'); + translationTimeout.value = meta.translationTimeout; deeplAuthKey.value = meta.deeplAuthKey; deeplIsPro.value = meta.deeplIsPro; deeplFreeMode.value = meta.deeplFreeMode; deeplFreeInstance.value = meta.deeplFreeInstance; libreTranslateURL.value = meta.libreTranslateURL; libreTranslateKey.value = meta.libreTranslateKey; + + watch(translationTimeout, async newValue => { + await os.apiWithDialog('admin/update-meta', { + translationTimeout: newValue, + }); + await os.promiseDialog(fetchInstance(true)); + }); } function save_deepl() { @@ -93,7 +107,7 @@ function save_deepl() { deeplFreeMode: deeplFreeMode.value, deeplFreeInstance: deeplFreeInstance.value, }).then(() => { - fetchInstance(true); + os.promiseDialog(fetchInstance(true)); }); } @@ -102,7 +116,7 @@ function save_libre() { libreTranslateURL: libreTranslateURL.value, libreTranslateKey: libreTranslateKey.value, }).then(() => { - fetchInstance(true); + os.promiseDialog(fetchInstance(true)); }); } diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 2b4c39c280..c8a15d32ec 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -9249,6 +9249,7 @@ export type operations = { enableReactionsBuffering: boolean; notesPerOneAd: number; backgroundImageUrl: string | null; + translationTimeout: number; deeplAuthKey: string | null; deeplIsPro: boolean; deeplFreeMode: boolean; @@ -12159,6 +12160,7 @@ export type operations = { maintainerName?: string | null; maintainerEmail?: string | null; langs?: string[]; + translationTimeout?: number; deeplAuthKey?: string | null; deeplIsPro?: boolean; deeplFreeMode?: boolean; diff --git a/sharkey-locales/en-US.yml b/sharkey-locales/en-US.yml index 0ebc3a9390..2788ba605e 100644 --- a/sharkey-locales/en-US.yml +++ b/sharkey-locales/en-US.yml @@ -564,3 +564,6 @@ wordMuteTestNoMatch: "Text does not match any patterns." bubbleTimeline: "Bubble timeline" bubbleTimelineDescription: "Choose which instances should be displayed in the bubble." bubbleTimelineMustBeEnabled: "Note: the bubble timeline is hidden by default, and must be enabled via roles." + +translationTimeoutLabel: "Translation timeout" +translationTimeoutCaption: "Timeout in milliseconds for translation API requests (default 5000)" |