feat: predict_tja script
This commit is contained in:
BIN
output/.DS_Store
vendored
BIN
output/.DS_Store
vendored
Binary file not shown.
74
output/xgboost_copy/features.json
Normal file
74
output/xgboost_copy/features.json
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"songno": "XODUS",
|
||||||
|
"difficulty": "oni",
|
||||||
|
"note_count": 1007,
|
||||||
|
"density_avg": 8.14959935897436,
|
||||||
|
"density_peak": 17,
|
||||||
|
"bpm_avg": 202,
|
||||||
|
"bpm_change": 0,
|
||||||
|
"scroll_change": 14,
|
||||||
|
"rhythm_complexity": 868,
|
||||||
|
"color_complexity": 0.012565274045963932
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"songno": "Destructive Little Sister",
|
||||||
|
"difficulty": "oni",
|
||||||
|
"note_count": 1119,
|
||||||
|
"density_avg": 7.917452830188679,
|
||||||
|
"density_peak": 21,
|
||||||
|
"bpm_avg": 247.5,
|
||||||
|
"bpm_change": 0,
|
||||||
|
"scroll_change": 17,
|
||||||
|
"rhythm_complexity": 1079,
|
||||||
|
"color_complexity": 0.016291673920775917
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"songno": "7 Wonders",
|
||||||
|
"difficulty": "oni",
|
||||||
|
"note_count": 794,
|
||||||
|
"density_avg": 5.571929824561403,
|
||||||
|
"density_peak": 12,
|
||||||
|
"bpm_avg": 168,
|
||||||
|
"bpm_change": 0,
|
||||||
|
"scroll_change": 0,
|
||||||
|
"rhythm_complexity": 726,
|
||||||
|
"color_complexity": 0.006656416024691356
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"songno": "7 Wonders",
|
||||||
|
"difficulty": "ura",
|
||||||
|
"note_count": 1207,
|
||||||
|
"density_avg": 8.47017543859649,
|
||||||
|
"density_peak": 15,
|
||||||
|
"bpm_avg": 168,
|
||||||
|
"bpm_change": 0,
|
||||||
|
"scroll_change": 0,
|
||||||
|
"rhythm_complexity": 965,
|
||||||
|
"color_complexity": 0.01463965596985236
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"songno": "Destruction 3 2 1",
|
||||||
|
"difficulty": "oni",
|
||||||
|
"note_count": 1160,
|
||||||
|
"density_avg": 7.46659375,
|
||||||
|
"density_peak": 15,
|
||||||
|
"bpm_avg": 321.3209999999973,
|
||||||
|
"bpm_change": 0,
|
||||||
|
"scroll_change": 5,
|
||||||
|
"rhythm_complexity": 1101,
|
||||||
|
"color_complexity": 0.012682773678672012
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"songno": "Destruction 3 2 1",
|
||||||
|
"difficulty": "ura",
|
||||||
|
"note_count": 1491,
|
||||||
|
"density_avg": 9.59714765625,
|
||||||
|
"density_peak": 20,
|
||||||
|
"bpm_avg": 321.32099999999707,
|
||||||
|
"bpm_change": 0,
|
||||||
|
"scroll_change": 8,
|
||||||
|
"rhythm_complexity": 1417,
|
||||||
|
"color_complexity": 0.028926671611070473
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -159,5 +159,6 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
predict(
|
predict(
|
||||||
args.workingDir,
|
args.workingDir,
|
||||||
args.songno
|
args.songno,
|
||||||
|
args.feature
|
||||||
)
|
)
|
||||||
@@ -1,51 +1,45 @@
|
|||||||
import tjaParser, { Bar, Branch, Course } from 'tja-parser'
|
import tjaParser, { Bar, Branch, Course } from 'tja-parser'
|
||||||
|
|
||||||
export function parseTja(tja: string): Partial<Record<'oni' | 'edit', Course>> | null {
|
export function parseTja(tja: string): Partial<Record<'oni' | 'edit', Course>> {
|
||||||
try {
|
const song = tjaParser.Song.parse(tja);
|
||||||
const song = tjaParser.Song.parse(tja);
|
|
||||||
|
|
||||||
let oni: Course | undefined = undefined;
|
let oni: Course | undefined = undefined;
|
||||||
let edit: Course | undefined = undefined;
|
let edit: Course | undefined = undefined;
|
||||||
|
|
||||||
if (song.course?.oni) {
|
if (song.course?.oni) {
|
||||||
const noteGroups = song.course.oni.noteGroups;
|
const noteGroups = song.course.oni.noteGroups;
|
||||||
oni = song.course.oni;
|
oni = song.course.oni;
|
||||||
oni.noteGroups = []
|
oni.noteGroups = []
|
||||||
|
|
||||||
for (const noteGroup of noteGroups) {
|
for (const noteGroup of noteGroups) {
|
||||||
if (noteGroup instanceof Bar) {
|
if (noteGroup instanceof Bar) {
|
||||||
oni.pushNoteGroups(noteGroup)
|
oni.pushNoteGroups(noteGroup)
|
||||||
}
|
}
|
||||||
else if (noteGroup instanceof Branch) {
|
else if (noteGroup instanceof Branch) {
|
||||||
const bar = noteGroup.master || noteGroup.advanced || noteGroup.normal;
|
const bar = noteGroup.master || noteGroup.advanced || noteGroup.normal;
|
||||||
if (bar) {
|
if (bar) {
|
||||||
oni.pushNoteGroups(...bar)
|
oni.pushNoteGroups(...bar)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (song.course?.edit) {
|
}
|
||||||
const noteGroups = song.course.edit.noteGroups;
|
if (song.course?.edit) {
|
||||||
edit = song.course.edit;
|
const noteGroups = song.course.edit.noteGroups;
|
||||||
edit.noteGroups = []
|
edit = song.course.edit;
|
||||||
|
edit.noteGroups = []
|
||||||
|
|
||||||
for (const noteGroup of noteGroups) {
|
for (const noteGroup of noteGroups) {
|
||||||
if (noteGroup instanceof Bar) {
|
if (noteGroup instanceof Bar) {
|
||||||
edit.pushNoteGroups(noteGroup)
|
edit.pushNoteGroups(noteGroup)
|
||||||
}
|
}
|
||||||
else if (noteGroup instanceof Branch) {
|
else if (noteGroup instanceof Branch) {
|
||||||
const bar = noteGroup.master || noteGroup.advanced || noteGroup.normal;
|
const bar = noteGroup.master || noteGroup.advanced || noteGroup.normal;
|
||||||
if (bar) {
|
if (bar) {
|
||||||
edit.pushNoteGroups(...bar)
|
edit.pushNoteGroups(...bar)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { oni, edit }
|
return { oni, edit }
|
||||||
}
|
|
||||||
catch (err){
|
|
||||||
console.error(err)
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
94
script/predict_tja.ts
Normal file
94
script/predict_tja.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import Bun from 'bun';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { parseArgs } from 'node:util';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import { featurize } from '../preprocess/featurize';
|
||||||
|
import { parseTja } from '../preprocess/parse';
|
||||||
|
|
||||||
|
const { values } = parseArgs({
|
||||||
|
args: Bun.argv,
|
||||||
|
options: {
|
||||||
|
tja: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
workingDir: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
script: {
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
allowPositionals: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!values.tja || !values.workingDir || !values.script) {
|
||||||
|
console.error("Usage: bun script/predict_tja.ts --tja <path_to_tja> [--workingDir <dir>] [--script <python_script>]");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tjaPath = values.tja;
|
||||||
|
if (!fs.existsSync(tjaPath)) {
|
||||||
|
console.error(`File not found: ${tjaPath}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const workingDir = values.workingDir!;
|
||||||
|
const pythonScript = values.script!;
|
||||||
|
|
||||||
|
if (!fs.existsSync(pythonScript)) {
|
||||||
|
console.error(`Python script not found: ${pythonScript}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. TJA 파싱 및 피처 추출
|
||||||
|
const tjaContent = fs.readFileSync(tjaPath, 'utf-8');
|
||||||
|
const songno = path.basename(tjaPath, '.tja');
|
||||||
|
const parsed = parseTja(tjaContent);
|
||||||
|
|
||||||
|
const features: any[] = [];
|
||||||
|
if (parsed.oni) {
|
||||||
|
features.push({
|
||||||
|
songno,
|
||||||
|
difficulty: 'oni',
|
||||||
|
...featurize(parsed.oni)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (parsed.edit) {
|
||||||
|
features.push({
|
||||||
|
songno,
|
||||||
|
difficulty: 'ura',
|
||||||
|
...featurize(parsed.edit)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (features.length === 0) {
|
||||||
|
console.error("No Oni or Ura difficulty found in the TJA file.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 임시 피처 파일 저장
|
||||||
|
const tempFeaturePath = path.join(workingDir, `temp_predict_${Date.now()}.json`);
|
||||||
|
fs.writeFileSync(tempFeaturePath, JSON.stringify(features, null, 2), 'utf-8');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 3. Python 예측 스크립트 실행
|
||||||
|
const proc = Bun.spawnSync([
|
||||||
|
"python3",
|
||||||
|
pythonScript,
|
||||||
|
"--workingDir", workingDir,
|
||||||
|
"--feature", tempFeaturePath,
|
||||||
|
"--songno", songno
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (proc.success) {
|
||||||
|
console.log(proc.stdout.toString());
|
||||||
|
} else {
|
||||||
|
console.error("Prediction failed:");
|
||||||
|
console.error(proc.stderr.toString());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// 4. 임시 파일 삭제
|
||||||
|
if (fs.existsSync(tempFeaturePath)) {
|
||||||
|
fs.unlinkSync(tempFeaturePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user