diff --git a/locales/index.d.ts b/locales/index.d.ts index a61913bf3e..77d857bdb1 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -730,6 +730,14 @@ export interface Locale extends ILocale { * にゃにゃにゃ?? */ "flagAsCatDescription": string; + /** + * 自動TTS機能が欲しい。 + */ + "flagAsVI": string; + /** + * 自動TTS機能が必要な場合は有効にしてください。 権限のあるユーザーグループに所属している場合、特定の範囲で自動TTS機能を有効にします。 + */ + "flagAsVIDescription": string; /** * タイムラインにノートへの返信を表示する */ @@ -6913,6 +6921,10 @@ export interface Locale extends ILocale { * botユーザー */ "isBot": string; + /** + * TTSユーザー + */ + "isVI": string; /** * サスペンド済みユーザー */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 544de32a73..fe1149b4c2 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -178,6 +178,8 @@ flagAsBot: "Botとして設定" flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったものになります。" flagAsCat: "にゃああああああああああああああ!!!!!!!!!!!!" flagAsCatDescription: "にゃにゃにゃ??" +flagAsVI: "自動TTS機能が欲しい。" +flagAsVIDescription: "自動TTS機能が必要な場合は有効にしてください。 権限のあるユーザーグループに所属している場合、特定の範囲で自動TTS機能を有効にします。" flagShowTimelineReplies: "タイムラインにノートへの返信を表示する" flagShowTimelineRepliesDescription: "オンにすると、タイムラインにユーザーのノート以外にもそのユーザーの他のノートへの返信を表示します。" autoAcceptFollowed: "フォロー中ユーザーからのフォロリクを自動承認" @@ -1786,6 +1788,7 @@ _role: isRemote: "リモートユーザー" isCat: "猫ユーザー" isBot: "botユーザー" + isVI: "TTSユーザー" isSuspended: "サスペンド済みユーザー" isLocked: "鍵アカウントユーザー" isExplorable: "「アカウントを見つけやすくする」が有効なユーザー" diff --git a/packages/backend/migration/1724683952000-tts.js b/packages/backend/migration/1724683952000-tts.js index 2b669804ae..60e8d29cc5 100644 --- a/packages/backend/migration/1724683952000-tts.js +++ b/packages/backend/migration/1724683952000-tts.js @@ -7,10 +7,13 @@ export class TTSIntegration1724683952000 { constructor() { this.name = 'TTSIntegration1724683952000'; } + async up(queryRunner) { await queryRunner.query(`ALTER TABLE "meta" ADD "hfAuthKey" character varying(128)`); } + async down(queryRunner) { await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfAuthKey"`); } } + diff --git a/packages/backend/migration/1724683962000-tts.js b/packages/backend/migration/1724683962000-tts.js new file mode 100644 index 0000000000..4881e0dd7b --- /dev/null +++ b/packages/backend/migration/1724683962000-tts.js @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class TTSIntegration1724683962000 { + constructor() { + this.name = 'TTSIntegration1724683962000'; + } + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "isVI" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`COMMENT ON COLUMN "user"."isVI" IS 'Whether the User needs auto TTS.'`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfSpace" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfSpaceName" character varying(128)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfexampleAudioURL" character varying(128)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfexampleText" character varying(128)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfexampleLang" character varying(128)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfslice" character varying(128) DEFAULT 'Slice once every 4 sentences'`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hftopK" INTEGER DEFAULT 15`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hftopP" NUMERIC(4, 2) DEFAULT 1.00`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfTemperature" NUMERIC(4, 2) DEFAULT 1.00`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfnrm" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfSpeedRate" NUMERIC(4, 2) DEFAULT 1.25`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfdas" boolean NOT NULL DEFAULT false`); + } + + async down(queryRunner) { + await queryRunner.query(`COMMENT ON COLUMN "user"."isVI" IS NULL`); + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isVI"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfSpace"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfSpaceName"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfexampleAudioURL"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfexampleText"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfexampleLang"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfslice"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hftopK"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hftopP"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfTemperature"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfnrm"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfSpeedRate"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfdas"`); + } +} + diff --git a/packages/backend/package.json b/packages/backend/package.json index c6e31797f8..29a9ada09c 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -79,6 +79,7 @@ "@fastify/multipart": "9.0.1", "@fastify/static": "8.0.1", "@fastify/view": "10.0.1", + "@gradio/client": "1.6.0-beta.3", "@misskey-dev/sharp-read-bmp": "1.2.0", "@misskey-dev/summaly": "5.1.0", "@napi-rs/canvas": "0.1.56", @@ -132,8 +133,8 @@ "json5": "2.2.3", "jsonld": "8.3.2", "jsrsasign": "11.1.0", - "meilisearch": "0.42.0", "juice": "11.0.0", + "meilisearch": "0.42.0", "mfm-js": "0.24.0", "microformats-parser": "2.0.2", "mime-types": "2.1.35", diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index fbcf532405..56b7fc6fc2 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -256,6 +256,10 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { case 'isCat': { return user.isCat; } + // Auto TTS + case 'isVI': { + return user.isVI; + } // 「ユーザを見つけやすくする」が有効なアカウント case 'isExplorable': { return user.isExplorable; diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index c9939adf11..ebeaa52664 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -490,6 +490,7 @@ export class UserEntityService implements OnModuleInit { }))) : [], isBot: user.isBot, isCat: user.isCat, + isVI: user.isVI, instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? { name: instance.name, softwareName: instance.softwareName, diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 1f8cfa6824..e7cc50bb1d 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -355,6 +355,72 @@ export class MiMeta { }) public hfAuthKey: string | null; + @Column('boolean', { + default: false, + }) + public hfSpace: boolean; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public hfSpaceName: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public hfexampleAudioURL: string; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public hfexampleText: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public hfexampleLang: string; + + @Column('varchar', { + length: 1024, + default: 'Slice once every 4 sentences', + nullable: true, + }) + public hfslice: string; + + @Column('varchar', { + default: 15, + }) + public hftopK: number; + + @Column('varchar', { + default: 1.00, + }) + public hftopP: number; + + @Column('varchar', { + default: 1.00, + }) + public hfTemperature: number; + + @Column('varchar', { + default: false, + }) + public hfnrm: boolean; + + @Column('varchar', { + default: 1.25, + }) + public hfSpeedRate: number; + + @Column('varchar', { + default: false, + }) + public hfdas: boolean; + @Column('varchar', { length: 1024, nullable: true, diff --git a/packages/backend/src/models/Role.ts b/packages/backend/src/models/Role.ts index a173971b2c..0e7c9f452b 100644 --- a/packages/backend/src/models/Role.ts +++ b/packages/backend/src/models/Role.ts @@ -83,6 +83,13 @@ type CondFormulaValueIsCat = { type: 'isCat'; }; +/** + * Auto TTS + */ +type CondFormulaValueIsVI = { + type: 'isVI'; +}; + /** * 「ユーザを見つけやすくする」が有効なアカウントの場合のみ成立とする */ @@ -164,6 +171,7 @@ export type RoleCondFormulaValue = { id: string } & ( CondFormulaValueIsLocked | CondFormulaValueIsBot | CondFormulaValueIsCat | + CondFormulaValueIsVI | CondFormulaValueIsExplorable | CondFormulaValueRoleAssignedTo | CondFormulaValueCreatedLessThan | diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 805a1e75ae..785a3ae334 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -184,6 +184,12 @@ export class MiUser { }) public isCat: boolean; + @Column('boolean', { + default: false, + comment: 'Whether the User needs auto TTS.', + }) + public isVI: boolean; + @Column('boolean', { default: false, comment: 'Whether the User is the root.', diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts index ead1f91814..0f86c763a7 100644 --- a/packages/backend/src/models/json-schema/role.ts +++ b/packages/backend/src/models/json-schema/role.ts @@ -66,7 +66,7 @@ export const packedRoleCondFormulaValueUserSettingBooleanSchema = { type: { type: 'string', nullable: false, optional: false, - enum: ['isSuspended', 'isLocked', 'isBot', 'isCat', 'isExplorable'], + enum: ['isSuspended', 'isLocked', 'isBot', 'isCat','isVI' , 'isExplorable'], }, }, } as const; diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 9cffd680f2..cd6ef5ec5e 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -115,6 +115,10 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + isVI: { + type: 'boolean', + nullable: false, optional: true, + }, instance: { type: 'object', nullable: false, optional: true, 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 ebd7895d8e..0a3db197f3 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -93,6 +93,18 @@ export const paramDef = { deeplAuthKey: { type: 'string', nullable: true }, deeplIsPro: { type: 'boolean' }, hfAuthKey: { type: 'string', nullable: true }, + hfSpace: { type: 'boolean', default: false }, + hfSpaceName: { type: 'string', length: 1024, nullable: true }, + hfexampleAudioURL: { type: 'string', length: 1024, nullable: true }, + hfexampleText: { type: 'string', length: 1024, nullable: true }, + hfexampleLang: { type: 'string', length: 1024, nullable: true }, + hfslice: { type: 'string', length: 1024, default: 'Slice once every 4 sentences', nullable: true }, + hftopK: { type: 'integer', default: 15 }, + hftopP: { type: 'numeric', precision: 4, scale: 2, default: 1.00 }, + hfTemperature: { type: 'numeric', precision: 4, scale: 2, default: 1.00 }, + hfnrm: { type: 'boolean', default: false }, + hfSpeedRate: { type: 'numeric', precision: 4, scale: 2, default: 1.25 }, + hfdas: { type: 'boolean', default: false }, enableEmail: { type: 'boolean' }, email: { type: 'string', nullable: true }, smtpSecure: { type: 'boolean' }, @@ -525,6 +537,74 @@ export default class extends Endpoint { // eslint- set.hfAuthKey = ps.hfAuthKey; } } + + if (ps.hfSpace !== undefined) { + set.hfSpace = ps.hfSpace; + } + + if (ps.hfSpaceName !== undefined) { + if (ps.hfSpaceName === '') { + set.hfSpaceName = null; + } else { + set.hfSpaceName = ps.hfSpaceName; + } + } + + if (ps.hfexampleAudioURL !== undefined) { + if (ps.hfexampleAudioURL === '') { + set.hfexampleAudioURL = null; + } else { + set.hfexampleAudioURL = ps.hfexampleAudioURL; + } + } + + if (ps.hfexampleText !== undefined) { + if (ps.hfexampleText === '') { + set.hfexampleText = null; + } else { + set.hfexampleText = ps.hfexampleText; + } + } + + if (ps.hfexampleLang !== undefined) { + if (ps.hfexampleLang === '') { + set.hfexampleLang = null; + } else { + set.hfexampleLang = ps.hfexampleLang; + } + } + + if (ps.hfslice !== undefined) { + if (ps.hfslice === '') { + set.hfslice = null; + } else { + set.hfslice = ps.hfslice; + } + } + + if (ps.hftopK !== undefined) { + set.hftopK = ps.hftopK; + } + + if (ps.hftopP !== undefined) { + set.hftopP = ps.hftopP; + } + + if (ps.hfTemperature !== undefined) { + set.hfTemperature = ps.hfTemperature; + } + + if (ps.hfnrm !== undefined) { + set.hfnrm = ps.hfnrm; + } + + if (ps.hfSpeedRate !== undefined) { + set.hfSpeedRate = ps.hfSpeedRate; + } + + if (ps.hfdas !== undefined) { + set.hfdas = ps.hfdas; + } if (ps.enableIpLogging !== undefined) { set.enableIpLogging = ps.enableIpLogging; diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 798bd98cf1..2871452b58 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -173,6 +173,7 @@ export const paramDef = { preventAiLearning: { type: 'boolean' }, isBot: { type: 'boolean' }, isCat: { type: 'boolean' }, + isVI: { type: 'boolean' }, injectFeaturedNote: { type: 'boolean' }, receiveAnnouncementEmail: { type: 'boolean' }, alwaysMarkNsfw: { type: 'boolean' }, @@ -323,6 +324,7 @@ export default class extends Endpoint { // eslint- if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning; if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat; + if (typeof ps.isVI === 'boolean') updates.isVI = ps.isVI; if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; if (typeof ps.alwaysMarkNsfw === 'boolean') { diff --git a/packages/backend/src/server/api/endpoints/notes/tts.ts b/packages/backend/src/server/api/endpoints/notes/tts.ts index 2012c0e190..8a64e2eaac 100644 --- a/packages/backend/src/server/api/endpoints/notes/tts.ts +++ b/packages/backend/src/server/api/endpoints/notes/tts.ts @@ -4,6 +4,7 @@ */ import { Injectable } from '@nestjs/common'; +import { Client } from "@gradio/client"; import { Endpoint } from '@/server/api/endpoint-base.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { MetaService } from '@/core/MetaService.js'; @@ -25,6 +26,11 @@ export const meta = { }, errors: { + incorrectconfig: { + message: 'Incorrect configuration.', + code: 'INCORRECT_CONFIG', + id: '8d171e60-83b8-11ef-b98c-a7506d6c1de4', + }, unavailable: { message: 'Convert of notes unavailable.', code: 'UNAVAILABLE', @@ -85,29 +91,85 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.unavailable); } - const endpoint = 'https://api-inference.huggingface.co/models/suno/bark'; + if (instance.hfSpace) { + const langlist = ['Chinese', 'English', 'Japanese', 'Yue', 'Korean', 'Chinese-English Mixed', 'Japanese-English Mixed', 'Yue-English Mixed', 'Korean-English Mixed', 'Multilingual Mixed', 'Multilingual Mixed(Yue)']; + const slicelist = ['No slice', 'Slice once every 4 sentences', 'Slice per 50 characters', 'Slice by Chinese punct', 'Slice by English punct', 'Slice by every punct']; + let exampleAudio; + let app; - const res = await this.httpRequestService.send(endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + instance.hfAuthKey, - Accept: 'audio/flac, */*', - }, - body: JSON.stringify({ - inputs: note.text, - }), - timeout: 60000, - }); + try { + const example = await fetch(instance.hfexampleAudioURL); + exampleAudio = await example.blob(); + } catch { + throw new ApiError(meta.errors.unavailable); + } - let contentType = res.headers.get('Content-Type') || 'application/octet-stream'; + if (((!instance.hfnrm) && (!instance.hfexampleText)) || (!langlist.includes(instance.hfexampleLang)) || (!slicelist.includes(instance.hfslice)) || (!instance.hfSpaceName) || (!(instance.hfSpeedRate >= 0.6 && instance.hfSpeedRate <= 1.65)) || (!(instance.hfTemperature >= 0 && instance.hfTemperature <= 1)) || (!(instance.hftopK >= 0 && instance.hftopK <= 100)) || (!(instance.hftopP >= 0 && instance.hftopP <= 1))) { + throw new ApiError(meta.errors.incorrectconfig); + } - if (contentType === 'audio/flac') { - return res.body; + try { + app = await Client.connect(instance.hfSpaceName, { hf_token: instance.hfAuthKey }); + } catch { + throw new ApiError(meta.errors.unavailable); + } + + const result = await app.predict("/get_tts_wav", [ + exampleAudio, + instance.hfexampleText, + instance.hfexampleLang, + note.text, + "Multilingual Mixed", + instance.hfslice, + instance.hftopK, + instance.hftopP, + instance.hfTemperature, + instance.hfnrm, + instance.hfSpeedRate, + instance.hfdas, + ]); + + let resurl = JSON.parse(result)[0].url; + + const res = await this.httpRequestService.send(resurl, { + method: 'POST', + headers: { + 'Authorization': 'Bearer ' + instance.hfAuthKey, + }, + timeout: 60000, + }); + + let contentType = res.headers.get('Content-Type') || 'application/octet-stream'; + + if (contentType === 'audio/flac') { + return res.body; + } else { + throw new ApiError(meta.errors.unavailable); + } } else { - throw new ApiError(meta.errors.unavailable); + const endpoint = 'https://api-inference.huggingface.co/models/suno/bark'; + + const res = await this.httpRequestService.send(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + instance.hfAuthKey, + Accept: 'audio/flac, */*', + }, + body: JSON.stringify({ + inputs: note.text, + }), + timeout: 60000, + }); + + let contentType = res.headers.get('Content-Type') || 'application/octet-stream'; + + if (contentType === 'audio/flac') { + return res.body; + } else { + throw new ApiError(meta.errors.unavailable); + } } - }); } } diff --git a/packages/frontend/src/components/MkTutorialDialog.Note.vue b/packages/frontend/src/components/MkTutorialDialog.Note.vue index 2a26d22dc2..0a04393452 100644 --- a/packages/frontend/src/components/MkTutorialDialog.Note.vue +++ b/packages/frontend/src/components/MkTutorialDialog.Note.vue @@ -52,6 +52,7 @@ const exampleNote = reactive({ avatarBlurhash: 'eiKmhHIByXxZ~qWXs:-pR*NbR*s:xuRjoL-oR*WCt6WWf6WVf6oeWB', isBot: false, isCat: true, + isVI: false, emojis: {}, onlineStatus: 'unknown', badgeRoles: [], diff --git a/packages/frontend/src/pages/admin/RolesEditorFormula.vue b/packages/frontend/src/pages/admin/RolesEditorFormula.vue index f001a4ac20..a334239b60 100644 --- a/packages/frontend/src/pages/admin/RolesEditorFormula.vue +++ b/packages/frontend/src/pages/admin/RolesEditorFormula.vue @@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only + diff --git a/packages/frontend/src/pages/admin/external-services.vue b/packages/frontend/src/pages/admin/external-services.vue index ee36958c95..38f7323901 100644 --- a/packages/frontend/src/pages/admin/external-services.vue +++ b/packages/frontend/src/pages/admin/external-services.vue @@ -5,36 +5,123 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -55,22 +142,66 @@ import MkFolder from '@/components/MkFolder.vue'; const deeplAuthKey = ref(''); const deeplIsPro = ref(false); const hfAuthKey = ref(''); +const hfSpace = ref(false); +const hfSpaceName = ref(null); +const hfexampleAudioURL = ref(null); +const hfexampleText = ref(null); +const hfexampleLang = ref(null); +const hfslice = ref('Slice once every 4 sentences'); +const hftopK = ref(15); +const hftopP = ref(1.00); +const hfTemperature = ref(1.00); +const hfnrm = ref(false); +const hfSpeedRate = ref(1.25); +const hfdas = ref(false); + async function init() { - const meta = await misskeyApi('admin/meta'); - deeplAuthKey.value = meta.deeplAuthKey; - deeplIsPro.value = meta.deeplIsPro; - hfAuthKey.value = meta.hfAuthkey; + const meta = await misskeyApi('admin/meta'); + deeplAuthKey.value = meta.deeplAuthKey; + deeplIsPro.value = meta.deeplIsPro; + hfAuthKey.value = meta.hfAuthkey; + hfSpace.value = meta.hfSpace, + hfSpaceName.value = meta.hfSpaceName, + hfexampleAudioURL.value = meta.hfexampleAudioURL, + hfexampleText.value = meta.hfexampleText, + hfexampleLang.value = meta.hfexampleLang, + hfslice.value = meta.hfslice, + hftopK.value = meta.hftopK, + hftopP.value = meta.hftopP, + hfTemperature.value = meta.hfTemperature, + hfnrm.value = meta.hfnrm, + hfSpeedRate.value = meta.hfSpeedRate, + hfdas.value = meta.hfdas, } function save_deepl() { - os.apiWithDialog('admin/update-meta', { - deeplAuthKey: deeplAuthKey.value, - deeplIsPro: deeplIsPro.value, - hfAuthKey: hfAuthKey.value, - }).then(() => { - fetchInstance(true); - }); + os.apiWithDialog('admin/update-meta', { + deeplAuthKey: deeplAuthKey.value, + deeplIsPro: deeplIsPro.value, + }).then(() => { + fetchInstance(true); + }); +} + +function save_tts() { + os.apiWithDialog('admin/update-meta', { + hfAuthKey: hfAuthKey.value, + hfSpace: hfSpace.value, + hfSpaceName: hfSpaceName.value, + hfexampleAudioURL: hfexampleAudioURL.value, + hfexampleText: hfexampleText.value, + hfexampleLang: hfexampleLang.value, + hfslice: hfslice.value, + hftopK: hftopK.value, + hftopP: hftopP.value, + hfTemperature: hfTemperature.value, + hfnrm: hfnrm.value, + hfSpeedRate: hfSpeedRate.value, + hfdas: hfdas.value, + }).then(() => { + fetchInstance(true); + }); } const headerActions = computed(() => []); @@ -78,7 +209,7 @@ const headerActions = computed(() => []); const headerTabs = computed(() => []); definePageMetadata(() => ({ - title: i18n.ts.externalServices, - icon: 'ti ti-link', + title: i18n.ts.externalServices, + icon: 'ti ti-link', })); diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 19c5d892de..db5266b53e 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -110,6 +110,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.flagAsCat }} {{ i18n.ts.flagAsBot }} + {{ i18n.ts.flagAsVI }}
@@ -151,6 +152,7 @@ const profile = reactive({ lang: $i.lang, isBot: $i.isBot ?? false, isCat: $i.isCat ?? false, + isVI: $i.isVI ?? false, }); watch(() => profile, () => { @@ -202,6 +204,7 @@ function save() { lang: profile.lang || null, isBot: !!profile.isBot, isCat: !!profile.isCat, + isVI: !!profile.isVI, }); globalEvents.emit('requestClearPageCache'); claimAchievement('profileFilled'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1312e8c886..1049a5d6ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -125,6 +125,9 @@ importers: '@fastify/view': specifier: 10.0.1 version: 10.0.1 + '@gradio/client': + specifier: 1.6.0-beta.3 + version: 1.6.0-beta.3(utf-8-validate@6.0.3) '@misskey-dev/sharp-read-bmp': specifier: 1.2.0 version: 1.2.0 @@ -1163,7 +1166,7 @@ importers: version: 7.17.0(eslint@9.11.0)(typescript@5.6.2) '@vitest/coverage-v8': specifier: 1.6.0 - version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0)) + version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.33.0)) '@vue/runtime-core': specifier: 3.5.11 version: 3.5.11 @@ -2772,6 +2775,10 @@ packages: resolution: {integrity: sha512-XrftRn4z75SnaJOmZQbt7Mk+IIjqVHw+glDGOxuHwXkZBZh/MBoRS7MHjSZMDaLhT4RjN2VqiEU7EOYleuJWSQ==} hasBin: true + '@gradio/client@1.6.0-beta.3': + resolution: {integrity: sha512-mJZVQ4UpfrSu71J4SkbSrpnbRotmB5ziy4fg7zqZhqXwXGZM3cHR9fUGkTFM0eXYnsaeBoiqn+1bcUh32Zcgkg==} + engines: {node: '>=18.0.0'} + '@hapi/boom@10.0.1': resolution: {integrity: sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==} @@ -4633,6 +4640,9 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/eventsource@1.1.15': + resolution: {integrity: sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==} + '@types/express-serve-static-core@4.17.33': resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==} @@ -6833,6 +6843,10 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + eventsource@2.0.2: + resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} + engines: {node: '>=12.0.0'} + execa@0.7.0: resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==} engines: {node: '>=4'} @@ -6975,6 +6989,9 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} + fetch-event-stream@0.1.5: + resolution: {integrity: sha512-V1PWovkspxQfssq/NnxoEyQo1DV+MRK/laPuPblIZmSjMN8P5u46OhlFQznSr9p/t0Sp8Uc6SbM3yCMfr0KU8g==} + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -10236,6 +10253,10 @@ packages: seedrandom@3.0.5: resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} + semiver@1.1.0: + resolution: {integrity: sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==} + engines: {node: '>=6'} + semver-regex@4.0.5: resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==} engines: {node: '>=12'} @@ -10806,6 +10827,9 @@ packages: textarea-caret@3.1.0: resolution: {integrity: sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==} + textlinestream@1.1.1: + resolution: {integrity: sha512-iBHbi7BQxrFmwZUQJsT0SjNzlLLsXhvW/kg7EyOMVMBIrlnj/qYofwo1LVLZi+3GbUEo96Iu2eqToI2+lZoAEQ==} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -13245,6 +13269,20 @@ snapshots: '@github/webauthn-json@2.1.1': {} + '@gradio/client@1.6.0-beta.3(utf-8-validate@6.0.3)': + dependencies: + '@types/eventsource': 1.1.15 + bufferutil: 4.0.7 + eventsource: 2.0.2 + fetch-event-stream: 0.1.5 + msw: 2.4.9(typescript@5.6.2) + semiver: 1.1.0 + textlinestream: 1.1.1 + typescript: 5.6.2 + ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + transitivePeerDependencies: + - utf-8-validate + '@hapi/boom@10.0.1': dependencies: '@hapi/hoek': 11.0.4 @@ -15573,6 +15611,8 @@ snapshots: '@types/estree@1.0.6': {} + '@types/eventsource@1.1.15': {} + '@types/express-serve-static-core@4.17.33': dependencies: '@types/node': 20.14.12 @@ -15962,7 +16002,7 @@ snapshots: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) eslint: 9.11.0 optionalDependencies: typescript: 5.5.4 @@ -15975,7 +16015,7 @@ snapshots: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) eslint: 9.11.0 optionalDependencies: typescript: 5.6.2 @@ -15988,7 +16028,7 @@ snapshots: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) eslint: 9.8.0 optionalDependencies: typescript: 5.6.2 @@ -16009,7 +16049,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) '@typescript-eslint/utils': 7.1.0(eslint@9.11.0)(typescript@5.3.3) - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) eslint: 9.11.0 ts-api-utils: 1.0.1(typescript@5.3.3) optionalDependencies: @@ -16021,7 +16061,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4) '@typescript-eslint/utils': 7.17.0(eslint@9.11.0)(typescript@5.5.4) - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) eslint: 9.11.0 ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: @@ -16033,7 +16073,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/utils': 7.17.0(eslint@9.11.0)(typescript@5.6.2) - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) eslint: 9.11.0 ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: @@ -16045,7 +16085,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2) '@typescript-eslint/utils': 7.17.0(eslint@9.8.0)(typescript@5.6.2) - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) eslint: 9.8.0 ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: @@ -16061,7 +16101,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -16076,7 +16116,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -16091,7 +16131,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.17.0 '@typescript-eslint/visitor-keys': 7.17.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -16175,7 +16215,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.2.1 '@bcoe/v8-coverage': 0.2.3 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.4 @@ -16190,11 +16230,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0))': + '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.33.0))': dependencies: '@ampproject/remapping': 2.2.1 '@bcoe/v8-coverage': 0.2.3 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.4 @@ -16205,7 +16245,7 @@ snapshots: std-env: 3.7.0 strip-literal: 2.1.0 test-exclude: 6.0.0 - vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0) + vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.33.0) transitivePeerDependencies: - supports-color @@ -16515,7 +16555,7 @@ snapshots: agent-base@7.1.0: dependencies: - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -17001,7 +17041,6 @@ snapshots: bufferutil@4.0.7: dependencies: node-gyp-build: 4.6.0 - optional: true bufferutil@4.0.8: dependencies: @@ -18638,6 +18677,8 @@ snapshots: events@3.3.0: {} + eventsource@2.0.2: {} + execa@0.7.0: dependencies: cross-spawn: 5.1.0 @@ -18885,6 +18926,8 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.2.1 + fetch-event-stream@0.1.5: {} + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -19487,7 +19530,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -19526,7 +19569,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color optional: true @@ -19534,14 +19577,14 @@ snapshots: https-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.0 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -19914,7 +19957,7 @@ snapshots: istanbul-lib-source-maps@5.0.4: dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -20315,6 +20358,35 @@ snapshots: jsdoc-type-pratt-parser@4.1.0: {} + jsdom@24.1.1: + dependencies: + cssstyle: 4.0.1 + data-urls: 5.0.0 + decimal.js: 10.4.3 + form-data: 4.0.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.12 + parse5: 7.1.2 + rrweb-cssom: 0.7.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.4 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + optional: true + jsdom@24.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3): dependencies: cssstyle: 4.0.1 @@ -21361,8 +21433,7 @@ snapshots: node-gyp-build-optional-packages@5.0.7: optional: true - node-gyp-build@4.6.0: - optional: true + node-gyp-build@4.6.0: {} node-gyp@10.2.0: dependencies: @@ -22741,6 +22812,8 @@ snapshots: seedrandom@3.0.5: {} + semiver@1.1.0: {} + semver-regex@4.0.5: {} semver-truncate@2.0.0: @@ -22889,7 +22962,7 @@ snapshots: dependencies: '@hapi/hoek': 11.0.4 '@hapi/wreck': 18.0.1 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) joi: 17.11.0 transitivePeerDependencies: - supports-color @@ -23376,6 +23449,8 @@ snapshots: textarea-caret@3.1.0: {} + textlinestream@1.1.1: {} + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -23849,7 +23924,7 @@ snapshots: vite-node@1.6.0(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0): dependencies: cac: 6.7.14 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) pathe: 1.1.2 picocolors: 1.0.1 vite: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0) @@ -23867,7 +23942,7 @@ snapshots: vite-node@1.6.0(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0): dependencies: cac: 6.7.14 - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) pathe: 1.1.2 picocolors: 1.0.1 vite: 5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0) @@ -23949,7 +24024,7 @@ snapshots: - supports-color - terser - vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0): + vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.33.0): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 @@ -23974,7 +24049,7 @@ snapshots: optionalDependencies: '@types/node': 20.14.12 happy-dom: 10.0.3 - jsdom: 24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4) + jsdom: 24.1.1 transitivePeerDependencies: - less - lightningcss @@ -24046,7 +24121,7 @@ snapshots: vue-eslint-parser@9.4.3(eslint@9.11.0): dependencies: - debug: 4.3.5(supports-color@5.5.0) + debug: 4.3.5(supports-color@8.1.1) eslint: 9.11.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3