Skip to content
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
1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@radix-ui/react-slot": "^1.2.0",
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.2.6",
"@repo/constants": "workspace:*",
"@repo/open-api": "workspace:*",
"@supabase/ssr": "^0.6.1",
"@supabase/supabase-js": "^2.49.1",
Expand Down
79 changes: 0 additions & 79 deletions apps/web/src/constants/artistAlias.ts

This file was deleted.

3 changes: 1 addition & 2 deletions apps/web/src/utils/getArtistAlias.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { artistAlias } from '@repo/constants';
import { getChoseong } from 'es-hangul';

import { artistAlias } from '@/constants/artistAlias';

export type SearchCandidate = { label: string; value: string };

const createCandidateList = (): SearchCandidate[] => {
Expand Down
18 changes: 18 additions & 0 deletions packages/constants/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@repo/constants",
"version": "1.0.0",
"description": "Shared domain constants across apps/packages",
"main": "./src/index.ts",
"exports": {
".": "./src/index.ts"
},
"type": "module",
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts"
},
"devDependencies": {
"@types/node": "^22.13.10",
"tsup": "^8.4.0",
"typescript": "^5.8.2"
}
}
79 changes: 79 additions & 0 deletions packages/constants/src/artistAlias.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
export const artistAlias = {
// 나무위키 데이터 추가

Aimer: ["에메", "에이머"],
amazarashi: ["아마자라시"],
"Bump of Chicken": ["범프 오브 치킨"],
ELLEGARDEN: ["엘레가든"],
"King Gnu": ["킹 누"],
LISA: ["리사"],
"Mrs. GREEN APPLE": ["미세스 그린 애플"],
RADWIMPS: ["래드윔프스"],
"SEKAI NO OWARI": ["세카이노 오와리", "세카오와"],
SPYAIR: ["스파이에어"],
Vaundy: ["바운디"],
YOASOBI: ["요아소비"],
"Creepy Nuts": ["크리피 너츠"],

// [Gemini 추천 아티스트 추가] 한국 인기 최상위
Ado: ["아도", "우세와", "신시대"],
imase: ["이마세", "나이트댄서"],
"ONE OK ROCK": ["원오크락", "원오크", "원옥"],
"X JAPAN": ["엑스재팬", "엑스제팬"],
"tuki.": ["츠키", "투키", "만찬가"],
HoneyWorks: ["허니웍스"],
"L'Arc~en~Ciel": ["라르크 앙 시엘", "라르크"],
松田聖子: ["마츠다 세이코"],
椎名林檎: ["시이나 링고"],
Eve: ["이브", "eve"],
美波: ["미나미", "minami", "373"],
"ASIAN KUNG-FU GENERATION": ["아시안 쿵푸 제너레이션", "아지캉", "아쿵제"],

// 기존 데이터
嵐: ["아라시"],
あいみょん: ["아이묭"],
米津玄師: ["요네즈 켄시"],
浜崎あゆみ: ["하마사키 아유미"],
水樹奈々: ["미즈키 나나"],
"モーニング娘。": ["모닝구 무스메"],
Official髭男dism: ["오피셜히게단디즘", "히게단", "프리텐더"],
ヨルシカ: ["요루시카"],
中島美嘉: ["나카시마 미카"],
宇多田ヒカル: ["우타다 히카루"],
西野カナ: ["니시노 카나"],
"関ジャニ∞": ["칸쟈니 에이트"],
"ずっと真夜中でいいのに。": ["즛토마요", "계속 한밤중이면 좋을텐데."],
倉木麻衣: ["쿠라키 마이"],
安室奈美惠: ["아무로 나미에"],
いきものがかり: ["이키모노가카리"],
星野源: ["호시노 겐"],
倖田來未: ["코다 쿠미"],
緑黄色社会: ["녹황색사회"],
坂本真綾: ["사카모토 마아야"],
結束バンド: ["결속 밴드"],
乃木坂46: ["노기자카46"],
林原めぐみ: ["하야시바라 메구미"],
ポルノグラフィティ: ["포르노그라피티"],
初音ミク: ["하츠네 미쿠"],
"DECO*27": ["DECO27", "데코니나"],
松浦亜弥: ["마츠우라 아야"],
堀江由衣: ["호리에 유이"],
コブクロ: ["코부쿠로"],
きゃりーぱみゅぱみゅ: ["캬리 파뮤파뮤"],
ももいろクローバーZ: ["모모이로 클로버 Z"],
キタニタツヤ: ["키타니 타츠야"],
優里: ["유우리"],
鈴木このみ: ["스즈키 코노미"],
菅田将暉: ["스다 마사키"],
スキマスイッチ: ["스키마스위치"],
"『ユイカ』": ["유이카"],
福山雅治: ["후쿠야마 마사하루"],
大塚愛: ["오오츠카 아이"],
米倉千尋: ["요네쿠라 치히로"],
"平井 堅": ["히라이 켄"],
藤井風: ["후지이 카제"],
田村ゆかり: ["타무라 유카리"],
オーイシマサヨシ: ["오이시 마사요시"],
ちゃんみな: ["챤미나"],
なとり: ["나토리"],
};
1 change: 1 addition & 0 deletions packages/constants/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { artistAlias } from './artistAlias';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Missing artistalias loader utility 📎 Requirement gap ⚙ Maintainability

@repo/constants only exports the raw artistAlias object, and no reusable loader exists to
produce an artist 원어 → aliases[0] lookup map. This forces each consumer to re-implement mapping
logic and risks inconsistent canonical-name selection.
Agent Prompt
## Issue description
A reusable loader utility for `artistAlias` (artist key → representative Korean name using `aliases[0]`) is required, but `@repo/constants` currently exports only the raw object and consumers rebuild the map themselves.

## Issue Context
The compliance requirement mandates a single, consistent rule for representative naming (`aliases[0]`) that can be reused across web/crawling.

## Fix Focus Areas
- packages/constants/src/index.ts[1-1]
- packages/crawling/src/cron/translationJpn.ts[21-24]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

19 changes: 19 additions & 0 deletions packages/constants/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"lib": ["ESNext"],
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"declarationDir": "./dist/types",
"declarationMap": true
},
"include": ["**/*.ts"],
"exclude": ["node_modules", "dist"]
}
1 change: 1 addition & 0 deletions packages/crawling/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"format": "prettier --write \"**/*.{ts,tsx,md}\""
},
"dependencies": {
"@repo/constants": "workspace:*",
"@repo/open-api": "workspace:*",
"@supabase/supabase-js": "^2.49.1",
"axios": "^1.5.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/crawling/src/cron/taggingSongs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ console.log('이미 태그된 곡 수:', taggedSongIds.size);

let processedCount = 0;
for (const song of allSongs) {
if (processedCount >= 5000) break;
if (processedCount >= 20000) break;
if (taggedSongIds.has(song.id)) {
resultsLog.skipped++;
continue;
Expand Down
37 changes: 28 additions & 9 deletions packages/crawling/src/cron/translationJpn.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { artistAlias } from '@repo/constants';

import { getJpopSongsForTranslationDB } from '@/supabase/getDB';
import { updateSongKoTranslationDB } from '@/supabase/updateDB';
import { translateJpnToKo } from '@/utils/translateJpnToKo';
Expand All @@ -6,6 +8,7 @@ const resultsLog = {
success: 0,
failed: 0,
skipped: 0,
usedAlias: 0,
};

// 히라가나, 카타카나, CJK 한자 범위로 일본어 포함 여부 판단
Expand All @@ -15,14 +18,18 @@ function containsJapanese(text: string): boolean {
return JAPANESE_REGEX.test(text);
}

// 1. J-POP 곡 조회
// artistAlias 로부터 artist 원어 → 한국어 대표 표기(별명 배열의 0번째) 맵 생성
const artistAliasMap = new Map<string, string>(
Object.entries(artistAlias).map(([artist, aliases]) => [artist, aliases[0]]),
);

const songs = await getJpopSongsForTranslationDB();

console.log('J-POP 곡 수:', songs.length);

let processedCount = 0;
for (const song of songs) {
if (processedCount >= 5000) break;
if (processedCount >= 10000) break;

// 이미 번역된 곡 스킵
if (song.title_ko && song.artist_ko) {
Expand All @@ -46,15 +53,26 @@ for (const song of songs) {
continue;
}

console.log(result);
// artistAlias 에 등록된 아티스트면 artist_ko 를 고정 값(alias 배열 0번째)으로 덮어쓰기
// title_ko 는 AI 번역 결과를 그대로 사용
const aliasArtistKo = artistAliasMap.get(song.artist);
const finalArtistKo = aliasArtistKo ?? result.artist_ko;

const success = await updateSongKoTranslationDB(song.id, result.title_ko, result.artist_ko);
if (success) {
resultsLog.success++;
console.log(`[OK] ${song.title} → ${result.title_ko} / ${song.artist} → ${result.artist_ko}`);
} else {
const success = await updateSongKoTranslationDB(song.id, result.title_ko, finalArtistKo);
Comment on lines +56 to +61
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. artistaliasmap applied after translation 📎 Requirement gap ➹ Performance

translationJpn.ts calls translateJpnToKo(song.title, song.artist) before checking the alias map,
so OpenAI is still used even when a fixed artist alias exists. This violates the requirement to
resolve artist via alias first and avoid translating the artist when an alias is present.
Agent Prompt
## Issue description
The cron invokes `translateJpnToKo` before alias resolution, so alias hits still incur OpenAI calls and still translate the artist.

## Issue Context
When an alias exists, `artist_ko` must come from the alias representative value (`aliases[0]`) and OpenAI should not be called for artist translation; only the title should be translated (and title should be kept as-is when it contains no Japanese).

## Fix Focus Areas
- packages/crawling/src/cron/translationJpn.ts[21-75]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

if (!success) {
resultsLog.failed++;
continue;
}

if (aliasArtistKo) {
resultsLog.usedAlias++;
} else {
resultsLog.success++;
}
const logPrefix = aliasArtistKo ? '[ALIAS]' : '[OK]';
console.log(
`${logPrefix} ${song.title} → ${result.title_ko} / ${song.artist} → ${finalArtistKo}`,
);
} catch (error) {
resultsLog.failed++;
console.error(`[ERROR] ${song.title} - ${song.artist}:`, error);
Expand All @@ -70,6 +88,7 @@ for (const song of songs) {
console.log(`
총 ${songs.length}곡 중:
- 스킵 (이미 번역됨): ${resultsLog.skipped}곡
- 성공: ${resultsLog.success}곡
- 성공 (AI 번역): ${resultsLog.success}곡
- 성공 (artist_ko alias 적용): ${resultsLog.usedAlias}곡
- 실패: ${resultsLog.failed}곡
`);
18 changes: 18 additions & 0 deletions pnpm-lock.yaml

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