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: 0 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.2.6",
"@repo/open-api": "workspace:*",
"@repo/query": "workspace:*",
"@supabase/ssr": "^0.6.1",
"@supabase/supabase-js": "^2.49.1",
"@tanstack/react-query": "^5.68.0",
Expand Down
111 changes: 111 additions & 0 deletions packages/crawling/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

일회성 데이터 수집/처리 스크립트 모음. 빌드 결과물을 배포하지 않으며, `tsx`로 스크립트를 직접 실행한다.

## Commands

```bash
pnpm ky-open # Open API(금영)로 KY 번호 수집
pnpm ky-youtube # YouTube 크롤링으로 KY 번호 수집 + AI 검증
pnpm ky-valid # 기존 KY 번호의 실제 존재 여부 재검증
pnpm ky-update # ky-youtube + ky-valid 병렬 실행
pnpm trans # 일본어 아티스트명 → 한국어 번역 후 DB 저장
pnpm test # vitest 실행
pnpm lint # ESLint
```

스크립트는 반드시 **`packages/crawling/`** 디렉토리에서 실행해야 한다. 로그 파일 및 assets 경로가 상대 경로 기준이기 때문.

## Environment Variables

`.env` 파일 필요 (루트가 아닌 `packages/crawling/`에 위치):

```
SUPABASE_URL=
SUPABASE_KEY=
OPENAI_API_KEY=
```

## Architecture

### 데이터 흐름

모든 스크립트는 **Supabase `songs` 테이블**을 중심으로 동작한다.

```
[songs 테이블]
title, artist, num_tj(TJ번호), num_ky(KY번호)

주요 목표: num_ky가 null인 곡에 KY 번호를 채우는 것
```

**KY 번호 수집 (메인 파이프라인)**

```
crawlYoutube.ts
└─ getSongsKyNullDB() # num_ky가 null인 곡 조회
└─ YouTube @KARAOKEKY 채널 검색 # puppeteer + cheerio로 번호 스크래핑
└─ isValidKYExistNumber() # kysing.kr에서 번호 실존 여부 확인
└─ validateSongMatch() # OpenAI gpt-4o-mini로 제목/아티스트 일치 판단
└─ updateSongsKyDB() # 성공 시 DB 업데이트
└─ postInvalidKYSongsDB() # 실패 시 invalid_ky_songs 테이블에 기록
```

**KY 번호 검증 (기존 데이터 재확인)**

```
crawlYoutubeValid.ts
└─ getSongsKyNotNullDB() # num_ky가 있는 곡 조회
└─ isValidKYExistNumber() # KY 사이트에서 실존 여부 재확인
└─ 유효하지 않으면 num_ky = null로 초기화
```

**Open API 방식 (보조)**

```
findKYByOpen.ts
└─ @repo/open-api의 getSong()으로 금영 API 직접 조회
└─ 제목 + 아티스트 문자열 비교로 KY 번호 매칭
```

**일본어 번역**

```
postTransDictionary.ts
└─ getSongsJpnDB() # 일본어 포함된 곡 필터링
└─ transChatGPT() # GPT-4-turbo로 아티스트명 번역
└─ postTransDictionariesDB() # trans_dictionaries 테이블에 저장
```

### 핵심 패턴: 진행 상태 저장 (체크포인트)

장시간 실행되는 스크립트가 중단됐을 때 재시작하면 처음부터 다시 하지 않도록, `src/assets/`에 텍스트 파일로 진행 상태를 기록한다.

| 파일 | 용도 |
|------|------|
| `src/assets/transList.txt` | 이미 번역 시도한 일본어 아티스트명 |
| `src/assets/crawlKYValidList.txt` | 검증 완료된 (제목-아티스트) 쌍 |
| `src/assets/crawlKYYoutubeFailedList.txt` | YouTube 크롤링 실패 목록 |

`logData.ts`의 `save*` / `load*` 함수로 관리. 스크립트 시작 시 로드해 `Set`으로 변환 후 O(1) 검색으로 스킵 처리.

### Path Alias

`@/` → `src/` (tsconfig의 paths 설정)

### Supabase 테이블

| 테이블 | 용도 |
|--------|------|
| `songs` | 메인 곡 데이터 (TJ/KY 번호 포함) |
| `invalid_ky_songs` | KY 번호 수집 실패 목록 |
| `trans_dictionaries` | 일본어 → 한국어 번역 사전 |

### AI 유틸

- `utils/validateSongMatch.ts` — `gpt-4o-mini`로 두 (제목, 아티스트) 쌍이 같은 곡인지 판단. `temperature: 0`, `max_tokens: 20`, 완전 일치 시 API 호출 생략.
- `utils/transChatGPT.ts` — `gpt-4-turbo`로 일본어 → 한국어 번역.
4 changes: 2 additions & 2 deletions packages/crawling/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"scripts": {
"ky-open": "tsx src/findKYByOpen.ts",
"ky-youtube": "tsx src/crawling/crawlYoutube.ts",
"ky-youtube-ubuntu": "tsx src/crawling/crawlYoutubeUbuntu.ts",
"ky-valid": "tsx src/crawling/crawlYoutubeValid.ts",
"ky-update": "pnpm run ky-youtube & pnpm run ky-valid",
"ky-verify": "tsx src/crawling/crawlYoutubeVerify.ts",
"ky-update": "pnpm run ky-youtube & pnpm run ky-valid & pnpm run ky-verify",
"trans": "tsx src/postTransDictionary.ts",
Comment on lines +13 to 15

Choose a reason for hiding this comment

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

Action required

1. Ky-update 실패 숨김 🐞 Bug ⛯ Reliability

ky-update&로 3개 스크립트를 백그라운드 병렬 실행해, 일부 작업이 실패해도 전체 명령이 성공으로 보일 수 있습니다(마지막 foreground 프로세스 exit
code만 반영). 결과적으로 크롤링/검증 실패가 탐지되지 않고 데이터 파이프라인이 부분 실패 상태로 남을 수 있습니다.
Agent Prompt
## Issue description
`ky-update` 스크립트가 `&` 백그라운드 실행을 사용하여 일부 작업 실패가 상위 명령의 실패로 전파되지 않을 수 있습니다. 이로 인해 크롤링/검증 파이프라인이 부분 실패해도 성공으로 보이는 문제가 발생합니다.

## Issue Context
현재 `ky-update`는 3개 스크립트를 병렬로 띄우되 실패 집계가 없습니다.

## Fix Focus Areas
- packages/crawling/package.json[9-16]

## Suggested changes
- (옵션 A, 안정) 순차 실행으로 변경: `pnpm run ky-youtube && pnpm run ky-valid && pnpm run ky-verify`
- (옵션 B, 병렬 유지) `concurrently`(또는 유사 툴) 도입 후 fail-fast/exit-code 집계 적용
- (옵션 C, 쉘 기반) 백그라운드 실행 후 `wait` 및 각 job의 종료코드 확인 로직 추가(가능하면 B 권장)

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

"recent-tj": "tsx src/crawling/crawlRecentTJ.ts",
"lint": "eslint . --ext .ts,.js",
Expand Down
4 changes: 1 addition & 3 deletions packages/crawling/src/crawling/crawlRecentTJ.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import puppeteer from 'puppeteer';

import { postSongsDB } from '@/supabase/postDB';
import { LogData, Song } from '@/types';
import { updateDataLog } from '@/utils/logData';
import { parseNumber } from '@/utils/parseNumber';
import { parseText } from '@/utils/parseString';

Expand Down Expand Up @@ -61,7 +60,6 @@ console.log('실패 개수 : ', result.failed.length);
console.log('성공 데이터 : ', result.success);
console.log('실패 데이터 : ', result.failed);

updateDataLog(result.success, 'postByRecentTJSuccess.txt');
updateDataLog(result.failed, 'postByRecentTJFailed.txt');


await browser.close();
109 changes: 0 additions & 109 deletions packages/crawling/src/crawling/crawlYoutubeTemp.ts

This file was deleted.

127 changes: 0 additions & 127 deletions packages/crawling/src/crawling/crawlYoutubeUbuntu.ts

This file was deleted.

Loading