From 4f6ce4970468afa5e7eda3a695e211d4d8fcf949 Mon Sep 17 00:00:00 2001 From: hotsixman Date: Sat, 25 Apr 2026 16:19:30 +0900 Subject: [PATCH] feat: predict_tja script --- output/.DS_Store | Bin 6148 -> 6148 bytes output/xgboost_copy/features.json | 74 +++++++++++++++++++++++ predict/predict_xgboost.py | 3 +- preprocess/parse.ts | 68 ++++++++++----------- script/predict_tja.ts | 94 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+), 38 deletions(-) create mode 100644 output/xgboost_copy/features.json create mode 100644 script/predict_tja.ts diff --git a/output/.DS_Store b/output/.DS_Store index 15006226cdc95d224470ab62a1273e4d5c32aa94..f7ab4a6b34bd92f2df65d8fded6b6960ed4b2a7a 100644 GIT binary patch delta 70 zcmZoMXfc@J&&aYdU^gQp%Vr)XZbqJ@^5TM|octsP28JDzb(jjdC910}j0|)X%uP)v auVj*D?3#R(NuIHLGb^(W%Vu_tzx)8Tpc8KZ delta 32 ocmZoMXfc@J&&a$nU^gQp^JX3> | null { - try { - const song = tjaParser.Song.parse(tja); +export function parseTja(tja: string): Partial> { + const song = tjaParser.Song.parse(tja); - let oni: Course | undefined = undefined; - let edit: Course | undefined = undefined; + let oni: Course | undefined = undefined; + let edit: Course | undefined = undefined; - if (song.course?.oni) { - const noteGroups = song.course.oni.noteGroups; - oni = song.course.oni; - oni.noteGroups = [] + if (song.course?.oni) { + const noteGroups = song.course.oni.noteGroups; + oni = song.course.oni; + oni.noteGroups = [] - for (const noteGroup of noteGroups) { - if (noteGroup instanceof Bar) { - oni.pushNoteGroups(noteGroup) - } - else if (noteGroup instanceof Branch) { - const bar = noteGroup.master || noteGroup.advanced || noteGroup.normal; - if (bar) { - oni.pushNoteGroups(...bar) - } + for (const noteGroup of noteGroups) { + if (noteGroup instanceof Bar) { + oni.pushNoteGroups(noteGroup) + } + else if (noteGroup instanceof Branch) { + const bar = noteGroup.master || noteGroup.advanced || noteGroup.normal; + if (bar) { + oni.pushNoteGroups(...bar) } } } - if (song.course?.edit) { - const noteGroups = song.course.edit.noteGroups; - edit = song.course.edit; - edit.noteGroups = [] + } + if (song.course?.edit) { + const noteGroups = song.course.edit.noteGroups; + edit = song.course.edit; + edit.noteGroups = [] - for (const noteGroup of noteGroups) { - if (noteGroup instanceof Bar) { - edit.pushNoteGroups(noteGroup) - } - else if (noteGroup instanceof Branch) { - const bar = noteGroup.master || noteGroup.advanced || noteGroup.normal; - if (bar) { - edit.pushNoteGroups(...bar) - } + for (const noteGroup of noteGroups) { + if (noteGroup instanceof Bar) { + edit.pushNoteGroups(noteGroup) + } + else if (noteGroup instanceof Branch) { + const bar = noteGroup.master || noteGroup.advanced || noteGroup.normal; + if (bar) { + edit.pushNoteGroups(...bar) } } } + } - return { oni, edit } - } - catch (err){ - console.error(err) - return null; - } + return { oni, edit } } \ No newline at end of file diff --git a/script/predict_tja.ts b/script/predict_tja.ts new file mode 100644 index 0000000..310f35f --- /dev/null +++ b/script/predict_tja.ts @@ -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 [--workingDir ] [--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); + } +}