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

refactor: TuningTranscriptionのコード量を削減 #2005

Merged
merged 8 commits into from
May 3, 2024
25 changes: 11 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
"clone-deep": "4.0.1",
"core-js": "3.12.1",
"dayjs": "1.10.7",
"diff": "5.1.0",
"electron-log": "5.0.0",
"electron-window-state": "5.0.3",
"encoding-japanese": "1.0.30",
"fast-array-diff": "1.1.0",
"glob": "8.0.3",
"hotkeys-js": "3.13.6",
"immer": "9.0.21",
Expand Down
102 changes: 24 additions & 78 deletions src/store/utility.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "path";
import { Platform } from "quasar";
import { diffArrays } from "diff";
import * as diff from "fast-array-diff";
import {
CharacterInfo,
StyleInfo,
Expand Down Expand Up @@ -216,8 +216,7 @@ function skipMemoText(targettext: string): string {
}

/**
* 2つのアクセント句配列を比べて同じだと思われるモーラの調整結果を転写し
* 変更前のアクセント句の調整結果を変更後のアクセント句に保持する。
* 調整したモーラのパラメーターがリセットされるのを防ぐ
*
* <例>
* 「こんにちは」 -> 「こんばんは」と変更した場合、[]に囲まれる部分で変更前のモーラが転写される。
Expand All @@ -231,81 +230,34 @@ export class TuningTranscription {
this.afterAccent = JSON.parse(JSON.stringify(afterAccent));
}

private createFlatArray<T, K extends keyof T>(
collection: T[],
key: K,
): T[K] extends (infer U)[] ? U[] : T[K][] {
const result = [];
for (const element of collection) {
const value = element[key];
if (Array.isArray(value)) {
result.push(...value);
} else {
result.push(value);
}
}
return result as T[K] extends (infer U)[] ? U[] : T[K][];
}

/**
* 変更前の配列を操作してpatchMora配列を作る。
*
* <例> (Uはundefined)
* 変更前 [ ズ, ン, ダ, モ, ン, ナ, ノ, ダ ]
* 変更後 [ ボ, ク, ズ, ン, ダ, ナ, ノ, デ, ス ]
*
* 再利用される文字列とundefinedで構成されたデータを作る。
* [ U, U, ズ, ン, ダ, ナ, ノ, U, U ]
*
* 実際には"ズ"などの文字列部分は{text: "ズ"...}のようなデータ構造になっている。
* [ U, U, {text: "ズ"...}, {text: "ン"...}, {text: "ダ"...}, {text: "ナ"...}, {text: "ノ"...}, U, U ]
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved
* 変更前と変更後のAccentPhraseに存在するモーラの差分を取得し
* 変更内容を適用したモーラの配列を返す
*/
private createDiffPatch() {
private createTranscriptionSource() {
const before = structuredClone(this.beforeAccent);
const after = structuredClone(this.afterAccent);
const beforeFlatArray = before.flatMap((accent) => accent.moras);
const afterFlatArray = after.flatMap((accent) => accent.moras);

const beforeFlatArray = this.createFlatArray(before, "moras");
const afterFlatArray = this.createFlatArray(after, "moras");
const diffed = diffArrays(
this.createFlatArray(beforeFlatArray, "text"),
this.createFlatArray(afterFlatArray, "text"),
const matchRequirements = (beforeMora: Mora, afterMora: Mora) =>
beforeMora?.text === afterMora?.text;

const morasDiff = diff.getPatch(
beforeFlatArray,
afterFlatArray,
matchRequirements, // beforeFlatArrayとafterFlatArrayの特定の要素が一致するかどうかを判定する関数
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved
);

// FIXME: beforeFlatArrayを破壊的に変更しなくても良いようにしてasを不要にする
let currentTextIndex = 0;
for (const diff of diffed) {
if (diff.removed) {
beforeFlatArray.splice(currentTextIndex, diff.count);
} else if (diff.added) {
diff.value.forEach(() => {
beforeFlatArray.splice(
currentTextIndex,
0,
undefined as never as Mora,
);
currentTextIndex++;
});
} else {
currentTextIndex += diff.value.length;
}
}
return beforeFlatArray as (Mora | undefined)[];
return diff.applyPatch(beforeFlatArray, morasDiff);
}

/**
* moraPatchとafterAccentを比較し、textが一致するモーラを転写する。
*
* <例> (「||」は等号記号を表す)
* 「こんにちは」 -> 「こんばんは」 とテキストを変更した場合、以下の例のように比較する。
*
* moraPatch = [ {text: "コ"...}, {text: "ン"...}, undefined , undefined , {text: "ハ"...} ]
* || || ||
* after[...]["moras"] = [ {text: "コ"...}, {text: "ン"...}, {text: "バ"...}, {text: "ン"...}, {text: "ハ"...} ]
*
* あとは一致したモーラを転写するだけ。
*
* transcriptionSourceで得られたモーラの配列を、変更後のAccentPhraseの各モーラに適用する
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved
*/
private mergeAccentPhrases(moraPatch: (Mora | undefined)[]): AccentPhrase[] {
private applyTranscriptionSource(
transcriptionSource: Mora[],
): AccentPhrase[] {
const after: AccentPhrase[] = structuredClone(this.afterAccent);
let moraPatchIndex = 0;

Expand All @@ -316,18 +268,12 @@ export class TuningTranscription {
moraIndex < after[accentIndex]["moras"].length;
moraIndex++
) {
// undefinedのとき、何もせず次のモーラへ移動
if (moraPatch[moraPatchIndex] == undefined) {
moraPatchIndex++;
continue;
}
if (
after[accentIndex]["moras"][moraIndex].text ===
moraPatch[moraPatchIndex]?.text
transcriptionSource[moraPatchIndex]?.text
) {
after[accentIndex]["moras"][moraIndex] = moraPatch[
moraPatchIndex
] as Mora;
after[accentIndex]["moras"][moraIndex] =
transcriptionSource[moraPatchIndex];
}
moraPatchIndex++;
}
Expand All @@ -337,8 +283,8 @@ export class TuningTranscription {
}

transcribe() {
const moraPatch = this.createDiffPatch();
return this.mergeAccentPhrases(moraPatch as never);
const transcriptionSource = this.createTranscriptionSource();
return this.applyTranscriptionSource(transcriptionSource);
}
}

Expand Down
Loading