Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CharacterInfoをエンジンから取って来るようにする #450

Merged
merged 12 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 2 additions & 57 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,10 @@ import { ipcMainHandle, ipcMainSend } from "@/electron/ipc";

import fs from "fs";
import {
CharacterInfo,
DefaultStyleId,
HotkeySetting,
MetasJson,
SavingSetting,
ThemeConf,
StyleInfo,
AcceptRetrieveTelemetryStatus,
} from "./type/preload";

Expand Down Expand Up @@ -309,48 +306,8 @@ if (!fs.existsSync(tempDir)) {
fs.mkdirSync(tempDir);
}

// キャラクター情報の読み込み
declare let __static: string;
const characterInfos: CharacterInfo[] = [];
for (const dirRelPath of fs.readdirSync(path.join(__static, "characters"))) {
const dirPath = path.join("characters", dirRelPath);
const policy = fs.readFileSync(
path.join(__static, dirPath, "policy.md"),
"utf-8"
);
const {
speakerName,
speakerUuid,
styles: stylesOrigin,
}: MetasJson = JSON.parse(
fs.readFileSync(path.join(__static, dirPath, "metas.json"), "utf-8")
);
const styles = stylesOrigin.map<StyleInfo>(({ styleName, styleId }) => ({
styleName,
styleId,
iconPath: path.join(dirPath, "icons", `${speakerName}_${styleId}.png`),
voiceSamplePaths: [...Array(3).keys()].map((x) =>
path.join(
dirPath,
"voice_samples",
`${speakerName}_${styleId}_${(x + 1).toString().padStart(3, "0")}.wav`
)
),
}));
const portraitPath = path.join(dirPath, "portrait.png");

characterInfos.push({
portraitPath,
metas: {
speakerName,
speakerUuid,
styles,
policy,
},
});
}

// 使い方テキストの読み込み
declare let __static: string;
const howToUseText = fs.readFileSync(
path.join(__static, "howtouse.md"),
"utf-8"
Expand Down Expand Up @@ -453,10 +410,6 @@ ipcMainHandle("GET_TEMP_DIR", () => {
return tempDir;
});

ipcMainHandle("GET_CHARACTER_INFOS", () => {
return characterInfos;
});

ipcMainHandle("GET_HOW_TO_USE_TEXT", () => {
return howToUseText;
});
Expand Down Expand Up @@ -723,15 +676,7 @@ ipcMainHandle("IS_UNSET_DEFAULT_STYLE_ID", (_, speakerUuid) => {
});

ipcMainHandle("GET_DEFAULT_STYLE_IDS", () => {
const defaultStyleIds = store.get("defaultStyleIds");
if (defaultStyleIds.length === 0) {
return characterInfos.map<DefaultStyleId>((info) => ({
speakerUuid: info.metas.speakerUuid,
defaultStyleId: info.metas.styles[0].styleId,
}));
} else {
return defaultStyleIds;
}
return store.get("defaultStyleIds");
});

ipcMainHandle("SET_DEFAULT_STYLE_IDS", (_, defaultStyleIds) => {
Expand Down
4 changes: 0 additions & 4 deletions src/electron/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ const api: Sandbox = {
return await ipcRendererInvoke("GET_APP_INFOS");
},

getCharacterInfos: async () => {
return await ipcRendererInvoke("GET_CHARACTER_INFOS");
},

getHowToUseText: async () => {
return await ipcRendererInvoke("GET_HOW_TO_USE_TEXT");
},
Expand Down
24 changes: 11 additions & 13 deletions src/openapi/models/SpeakerInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
*/

import { exists, mapValues } from '../runtime';
import {
StyleInfo,
StyleInfoFromJSON,
StyleInfoFromJSONTyped,
StyleInfoToJSON
} from "./";
/**
* 話者の追加情報
* @export
Expand All @@ -33,16 +39,10 @@ export interface SpeakerInfo {
portrait: string;
/**
*
* @type {{ [key: string]: string; }}
* @memberof SpeakerInfo
*/
icons: { [key: string]: string; };
/**
*
* @type {{ [key: string]: string; }}
* @memberof SpeakerInfo
* @type Array<StyleInfo>
* @memberof StyleInfos
*/
voiceSamples: { [key: string]: string; };
styleInfos: Array<StyleInfo>;
}

export function SpeakerInfoFromJSON(json: any): SpeakerInfo {
Expand All @@ -57,8 +57,7 @@ export function SpeakerInfoFromJSONTyped(json: any, ignoreDiscriminator: boolean

'policy': json['policy'],
'portrait': json['portrait'],
'icons': json['icons'],
'voiceSamples': json['voice_samples'],
'styleInfos': ((json['style_infos'] as Array<any>).map(StyleInfoFromJSON)),
};
}

Expand All @@ -73,8 +72,7 @@ export function SpeakerInfoToJSON(value?: SpeakerInfo | null): any {

'policy': value.policy,
'portrait': value.portrait,
'icons': value.icons,
'voice_samples': value.voiceSamples,
'style_infos': ((value.styleInfos as Array<any>).map(StyleInfoToJSON)),
};
}

Expand Down
73 changes: 73 additions & 0 deletions src/openapi/models/StyleInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* tslint:disable */
/* eslint-disable */
/**
* VOICEVOX ENGINE
* VOICEVOXの音声合成エンジンです。
*
* The version of the OpenAPI document: 0.8.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

import { exists, mapValues } from '../runtime';
/**
* engineから得られる話者のスタイル情報
* @export
* @interface StyleInfo
*/
export interface StyleInfo {
/**
*
* @type {number}
* @memberof StyleInfo
*/
id: number;
/**
*
* @type {string}
* @memberof StyleInfo
*/
icon: string;
/**
*
* @type {Array<string>}
* @memberof StyleInfo
*/
voiceSamples: Array<string>;
}

export function StyleInfoFromJSON(json: any): StyleInfo {
return StyleInfoFromJSONTyped(json, false);
}

export function StyleInfoFromJSONTyped(json: any, ignoreDiscriminator: boolean): StyleInfo {
if ((json === undefined) || (json === null)) {
return json;
}
return {

'id': json['id'],
'icon': json['icon'],
'voiceSamples': json['voice_samples'],
};
}

export function StyleInfoToJSON(value?: StyleInfo | null): any {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return {

'id': value.id,
'icon': value.icon,
'voice_samples': value.voiceSamples,
};
}


1 change: 1 addition & 0 deletions src/openapi/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export * from "./Preset";
export * from "./Speaker";
export * from "./SpeakerInfo";
export * from "./SpeakerStyle";
export * from "./StyleInfo";
export * from "./ValidationError";
69 changes: 66 additions & 3 deletions src/store/audio.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AudioQuery, AccentPhrase } from "@/openapi";
import { AudioQuery, AccentPhrase, Speaker, SpeakerInfo } from "@/openapi";
import path from "path";
import { v4 as uuidv4 } from "uuid";
import {
Expand All @@ -23,6 +23,7 @@ import {
CharacterInfo,
Encoding as EncodingType,
MoraDataType,
StyleInfo,
} from "@/type/preload";
import Encoding from "encoding-japanese";
import { PromiseType } from "./vuex";
Expand Down Expand Up @@ -417,8 +418,70 @@ export const audioStore: VoiceVoxStoreOptions<
}
}
),
LOAD_CHARACTER: createUILockAction(async ({ commit }) => {
const characterInfos = await window.electron.getCharacterInfos();
LOAD_CHARACTER: createUILockAction(async ({ commit, dispatch }) => {
const speakers = await dispatch("INVOKE_ENGINE_CONNECTOR", {
action: "speakersSpeakersGet",
payload: [],
})
.then(toDispatchResponse("speakersSpeakersGet"))
.catch((error) => {
window.electron.logError(error, `Failed to get speakers.`);
throw error;
});
const base64ToUrl = function (base64: string, type: string) {
const buffer = Buffer.from(base64, "base64");
const iconBlob = new Blob([buffer.buffer], { type: type });
return URL.createObjectURL(iconBlob);
};
const getStyles = function (speaker: Speaker, speakerInfo: SpeakerInfo) {
const styles: StyleInfo[] = new Array(speaker.styles.length);
speaker.styles.forEach((style, i) => {
const styleInfo = speakerInfo.styleInfos.find(
(styleInfo) => style.id === styleInfo.id
);
if (!styleInfo)
throw new Error(
`Not found the style id "${style.id}" of "${speaker.name}". `
);
const voiceSamples = styleInfo.voiceSamples.map((voiceSample) => {
return base64ToUrl(voiceSample, "audio/wav");
});
styles[i] = {
styleName: style.name,
styleId: style.id,
iconPath: base64ToUrl(styleInfo.icon, "image/png"),
voiceSamplePaths: voiceSamples,
};
});
return styles;
};
const getSpeakerInfo = async function (speaker: Speaker) {
const speakerInfo = await dispatch("INVOKE_ENGINE_CONNECTOR", {
action: "speakerInfoSpeakerInfoGet",
payload: [{ speakerUuid: speaker.speakerUuid }],
})
.then(toDispatchResponse("speakerInfoSpeakerInfoGet"))
.catch((error) => {
window.electron.logError(error, `Failed to get speakers.`);
throw error;
});
const styles = getStyles(speaker, speakerInfo);
const characterInfo: CharacterInfo = {
portraitPath: base64ToUrl(speakerInfo.portrait, "image/png"),
metas: {
speakerUuid: speaker.speakerUuid,
speakerName: speaker.name,
styles: styles,
policy: speakerInfo.policy,
},
};
return characterInfo;
};
const characterInfos: CharacterInfo[] = await Promise.all(
speakers.map(async (speaker) => {
return await getSpeakerInfo(speaker);
})
);

commit("SET_CHARACTER_INFOS", { characterInfos });
}),
Expand Down
20 changes: 17 additions & 3 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { projectStoreState, projectStore } from "./project";
import { uiStoreState, uiStore } from "./ui";
import { settingStoreState, settingStore } from "./setting";
import { proxyStore, proxyStoreState } from "./proxy";
import { DefaultStyleId } from "@/type/preload";

const isDevelopment = process.env.NODE_ENV == "development";

Expand Down Expand Up @@ -95,9 +96,22 @@ export const indexStore: VoiceVoxStoreOptions<
async IS_UNSET_DEFAULT_STYLE_ID(_, { speakerUuid }) {
return await window.electron.isUnsetDefaultStyleId(speakerUuid);
},
async LOAD_DEFAULT_STYLE_IDS({ commit }) {
const defaultStyleIds = await window.electron.getDefaultStyleIds();
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved
commit("SET_DEFAULT_STYLE_IDS", { defaultStyleIds });
async LOAD_DEFAULT_STYLE_IDS({ commit, state }) {
const storeDefaultStyleIds = await window.electron.getDefaultStyleIds();
if (storeDefaultStyleIds.length === 0) {
const characterInfos = await state.characterInfos;
if (characterInfos == undefined)
throw new Error("state.characterInfos == undefined");
const defaultStyleIds = characterInfos.map<DefaultStyleId>((info) => ({
speakerUuid: info.metas.speakerUuid,
defaultStyleId: info.metas.styles[0].styleId,
}));
commit("SET_DEFAULT_STYLE_IDS", { defaultStyleIds });
} else {
commit("SET_DEFAULT_STYLE_IDS", {
defaultStyleIds: storeDefaultStyleIds,
});
}
},
async SET_DEFAULT_STYLE_IDS({ commit }, defaultStyleIds) {
commit("SET_DEFAULT_STYLE_IDS", { defaultStyleIds });
Expand Down
5 changes: 0 additions & 5 deletions src/type/ipc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ type IpcIHData = {
return: string;
};

GET_CHARACTER_INFOS: {
args: [];
return: import("@/type/preload").CharacterInfo[];
};

GET_HOW_TO_USE_TEXT: {
args: [];
return: string;
Expand Down
1 change: 0 additions & 1 deletion src/type/preload.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { IpcRenderer, IpcRendererEvent } from "electron";

export interface Sandbox {
getAppInfos(): Promise<AppInfos>;
getCharacterInfos(): Promise<CharacterInfo[]>;
getHowToUseText(): Promise<string>;
getPolicyText(): Promise<string>;
getOssLicenses(): Promise<Record<string, string>[]>;
Expand Down
8 changes: 4 additions & 4 deletions src/views/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -351,10 +351,10 @@ export default defineComponent({

// プロジェクトを初期化
onMounted(async () => {
await Promise.all([
store.dispatch("LOAD_CHARACTER"),
store.dispatch("LOAD_DEFAULT_STYLE_IDS"),
]);
await store.dispatch("START_WAITING_ENGINE");
await store.dispatch("LOAD_CHARACTER");
await store.dispatch("LOAD_DEFAULT_STYLE_IDS");

let isUnsetDefaultStyleIds = false;
if (characterInfos.value == undefined) throw new Error();
for (const info of characterInfos.value) {
Expand Down