diff --git a/packages/backend/migration/1724683962000-tts.js b/packages/backend/migration/1724683962000-tts.js index 4881e0dd7b..a2e21847ee 100644 --- a/packages/backend/migration/1724683962000-tts.js +++ b/packages/backend/migration/1724683962000-tts.js @@ -18,10 +18,10 @@ export class TTSIntegration1724683962000 { 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 "hftopP" INTEGER DEFAULT 100`); + await queryRunner.query(`ALTER TABLE "meta" ADD "hfTemperature" INTEGER DEFAULT 100`); 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 "hfSpeedRate" INTEGER DEFAULT 125`); await queryRunner.query(`ALTER TABLE "meta" ADD "hfdas" boolean NOT NULL DEFAULT false`); } diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index e7cc50bb1d..99c3d2442a 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -370,7 +370,7 @@ export class MiMeta { length: 1024, nullable: true, }) - public hfexampleAudioURL: string; + public hfexampleAudioURL: string | null; @Column('varchar', { length: 1024, @@ -382,41 +382,41 @@ export class MiMeta { length: 1024, nullable: true, }) - public hfexampleLang: string; + public hfexampleLang: string | null; @Column('varchar', { length: 1024, default: 'Slice once every 4 sentences', nullable: true, }) - public hfslice: string; + public hfslice: string | null; - @Column('varchar', { + @Column('integer', { default: 15, }) public hftopK: number; - @Column('varchar', { - default: 1.00, + @Column('integer', { + default: 100, }) public hftopP: number; - @Column('varchar', { - default: 1.00, + @Column('integer', { + default: 100, }) public hfTemperature: number; - @Column('varchar', { + @Column('boolean', { default: false, }) public hfnrm: boolean; - @Column('varchar', { - default: 1.25, + @Column('integer', { + default: 125, }) public hfSpeedRate: number; - @Column('varchar', { + @Column('boolean', { default: false, }) public hfdas: boolean; 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 0a3db197f3..868269d1a6 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -94,16 +94,16 @@ export const paramDef = { 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 }, + hfSpaceName: { type: 'string', nullable: true }, + hfexampleAudioURL: { type: 'string', nullable: true }, + hfexampleText: { type: 'string', nullable: true }, + hfexampleLang: { type: 'string', nullable: true }, + hfslice: { type: 'string', 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 }, + hftopP: { type: 'integer', default: 100 }, + hfTemperature: { type: 'integer', default: 100 }, hfnrm: { type: 'boolean', default: false }, - hfSpeedRate: { type: 'numeric', precision: 4, scale: 2, default: 1.25 }, + hfSpeedRate: { type: 'integer', default: 125 }, hfdas: { type: 'boolean', default: false }, enableEmail: { type: 'boolean' }, email: { type: 'string', nullable: true }, diff --git a/packages/backend/src/server/api/endpoints/notes/tts.ts b/packages/backend/src/server/api/endpoints/notes/tts.ts index 8a64e2eaac..7d5c25c190 100644 --- a/packages/backend/src/server/api/endpoints/notes/tts.ts +++ b/packages/backend/src/server/api/endpoints/notes/tts.ts @@ -91,6 +91,8 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.unavailable); } + let outofQuota; + 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']; @@ -98,13 +100,13 @@ export default class extends Endpoint { // eslint- let app; try { - const example = await fetch(instance.hfexampleAudioURL); + const example = await fetch(instance.hfexampleAudioURL || ''); exampleAudio = await example.blob(); } catch { throw new ApiError(meta.errors.unavailable); } - 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))) { + if (((!instance.hfnrm) && (!instance.hfexampleText)) || (!langlist.includes(instance.hfexampleLang || '')) || (!slicelist.includes(instance.hfslice || '')) || (!instance.hfSpaceName) || (!(instance.hfSpeedRate >= 60 && instance.hfSpeedRate <= 165)) || (!(instance.hfTemperature >= 0 && instance.hfTemperature <= 100)) || (!(instance.hftopK >= 0 && instance.hftopK <= 100)) || (!(instance.hftopP >= 0 && instance.hftopP <= 100))) { throw new ApiError(meta.errors.incorrectconfig); } @@ -114,39 +116,60 @@ export default class extends Endpoint { // eslint- 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 result; + let notcontinue; - let resurl = JSON.parse(result)[0].url; + try { + result = await app.predict("/get_tts_wav", [ + exampleAudio, + instance.hfexampleText, + instance.hfexampleLang, + note.text, + "Multilingual Mixed", + instance.hfslice, + instance.hftopK, + instance.hftopP / 100, + instance.hfTemperature / 100, + instance.hfnrm, + instance.hfSpeedRate / 100, + instance.hfdas, + ]); + } catch (e) { + console.error("An error occurred during prediction:", e); - const res = await this.httpRequestService.send(resurl, { - method: 'POST', - headers: { - 'Authorization': 'Bearer ' + instance.hfAuthKey, - }, - timeout: 60000, - }); + const responseMessage = (e as any).message || ((e as any).original_msg && (e as any).original_msg.message); - let contentType = res.headers.get('Content-Type') || 'application/octet-stream'; - - if (contentType === 'audio/flac') { - return res.body; - } else { - throw new ApiError(meta.errors.unavailable); + if (responseMessage && responseMessage.includes('You have exceeded your GPU quota')) { + outofQuota = true; + console.log("Fallback to Inference API"); + } + notcontinue = true; } - } else { + + if (!notcontinue) { + let resurl = result.data[0].url; + + const res = await this.httpRequestService.send(resurl, { + method: 'GET', + headers: { + 'Authorization': 'Bearer ' + instance.hfAuthKey, + }, + timeout: 60000, + }); + + let contentType = res.headers.get('Content-Type') || 'application/octet-stream'; + + console.log(contentType); + + if (contentType === 'audio/x-wav') { + return res.body; + } else { + throw new ApiError(meta.errors.unavailable); + } + } + } + + if ((!instance.hfSpace) || ((instance.hfSpace) && (outofQuota))) { const endpoint = 'https://api-inference.huggingface.co/models/suno/bark'; const res = await this.httpRequestService.send(endpoint, { diff --git a/packages/frontend/src/pages/admin/external-services.vue b/packages/frontend/src/pages/admin/external-services.vue index 38f7323901..ee3e524a8b 100644 --- a/packages/frontend/src/pages/admin/external-services.vue +++ b/packages/frontend/src/pages/admin/external-services.vue @@ -40,16 +40,18 @@ SPDX-License-Identifier: AGPL-3.0-only +
+
- - + +
- - - - - - - - - - + + + + + + + + + + + + + Save @@ -130,6 +106,7 @@ import { ref, computed } from 'vue'; import XHeader from './_header_.vue'; import MkInput from '@/components/MkInput.vue'; import MkButton from '@/components/MkButton.vue'; +import MkSelect from '@/components/MkSelect.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import FormSuspense from '@/components/form/suspense.vue'; import * as os from '@/os.js'; @@ -149,10 +126,10 @@ 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 hftopP = ref(100); +const hfTemperature = ref(100); const hfnrm = ref(false); -const hfSpeedRate = ref(1.25); +const hfSpeedRate = ref(125); const hfdas = ref(false); @@ -172,7 +149,7 @@ async function init() { hfTemperature.value = meta.hfTemperature, hfnrm.value = meta.hfnrm, hfSpeedRate.value = meta.hfSpeedRate, - hfdas.value = meta.hfdas, + hfdas.value = meta.hfdas } function save_deepl() {