Commit Graph

354 Commits

Author SHA1 Message Date
5f5010ded4 fix(music-lab): video encoder timeout을 duration에 비례 (긴 mix 인코딩 지원) 2026-05-10 17:10:27 +09:00
755dea63f4 fix(music-lab): cache-buster query 제거 + DALL·E prompt에 background_keyword 활용
1. video.py _container_to_nas, orchestrator.py _local_path에서 path 변환 전 ?쿼리 strip
   — 이전 commit 20c5268의 cache-buster ?v=...가 Windows path로 그대로 전달되어 input_validation 실패하던 문제 픽스
2. cover.py _generate_with_dalle가 background_keyword를 prompt에 포함
   — 사용자가 PipelineStartModal에서 '배경 키워드' 입력 시 처음부터 원하는 분위기 cover 생성
2026-05-10 16:12:21 +09:00
20c5268def fix(music-lab): pipeline media URL에 cache-buster — regen 시 브라우저/텔레그램 캐시 우회 2026-05-10 15:50:42 +09:00
dc3f9cb6a9 fix(music-lab): compile job status='done'도 ready로 인식 (production convention) 2026-05-10 15:28:08 +09:00
262366bc1e test(music-lab): compile_job 기반 happy path 통합 테스트 2026-05-09 13:27:47 +09:00
5fc914cd8f feat(music-lab): POST /pipeline에 compile_job_id + visual_style/background 옵션 2026-05-09 13:20:38 +09:00
8f859274c4 feat(music-lab): video.py — Windows에 style/background_mode/tracks 전달 + orchestrator 파라미터 wiring 2026-05-09 13:17:49 +09:00
a347da075c feat(music-lab): metadata tracks 옵션 + YouTube 챕터 자동 형식 2026-05-09 13:15:30 +09:00
e754fb30f5 feat(music-lab): background.py — Pexels Video API + orchestrator video_loop 분기 2026-05-09 13:13:42 +09:00
f0c0c18beb feat(music-lab): cover.py Pexels 이미지 검색 분기 (image_source=pexels) 2026-05-09 13:10:49 +09:00
d11023decb feat(music-lab): orchestrator _resolve_input — track/compile_job 통합 입력 2026-05-09 13:08:53 +09:00
70a256bbe4 feat(music-lab): video_pipelines 4 컬럼 추가 + compile_jobs JOIN
- _add_column_if_missing 헬퍼 추가 (idempotent ALTER TABLE)
- video_pipelines에 compile_job_id, visual_style, background_mode, background_keyword 컬럼 추가
- track_id를 nullable로 변경 (compile_job_id 입력 모드 지원)
- create_pipeline에 compile_job_id XOR track_id 검증 추가
- get_pipeline / list_pipelines에 compile_jobs LEFT JOIN — compile_title 노출

Task 1 of 17: Essential Mix pipeline DB migration

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 13:04:23 +09:00
ebbfa6299a docs(plan): Essential Mix 파이프라인 — 17 task 구현 계획
DB 마이그레이션 → orchestrator _resolve_input → cover Pexels 분기 →
background.py 신규 → metadata tracks → video.py 파라미터 확장 →
main.py compile_job_id → Windows essential filter (showfreqs+ring+drawtext) →
server.py schema → 통합 테스트 → 배포 → 프론트(api.js, CompileTab,
PipelineStartModal, PipelineCard+DetailModal, SetupTab) → 프론트 푸시 → E2E.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:44:02 +09:00
d4fb485931 docs(spec): Essential Mix 파이프라인 설계
1시간+ mix 영상(컴파일 → 파이프라인) + essential 시각 스타일(배경 사진 + 중앙 방사형 막대 + 곡명 자막) + 진행 탭 산출물 미리보기 모달.

핵심 결정:
- 입력: track_id XOR compile_job_id
- 시각: single (기존) / essential (신규, default)
- 배경: static(사진) / video_loop(Pexels 영상)
- 배경 소스: AI 기본 + Pexels 폴백
- Mix 메타: 트랙 리스트 자동 챕터화 (YouTube 자동 인식)
- UX: PipelineCard mini 미리보기 + 클릭 시 상세 모달

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:55:24 +09:00
b6dffb4d42 chore(infra): GPU 영상 인코더 env 추가 (WINDOWS_VIDEO_ENCODER_URL, NAS_VIDEOS_ROOT, NAS_MUSIC_ROOT) 2026-05-09 02:03:26 +09:00
240bd38541 feat(music-lab): 영상 인코딩을 Windows GPU 서버로 오프로드
- pipeline/video.py 재작성: subprocess.run 제거, httpx로 Windows /encode_video 호출
- Windows 서버 다운 시 즉시 VideoGenerationError (NAS 로컬 폴백 X — 의도적 결정)
- /app/data/* → /volume1/docker/webpage/data/* 경로 변환 (_container_to_nas)
- 테스트는 respx mock 기반으로 교체 (6개)
2026-05-09 02:01:34 +09:00
bb0b0dff25 docs: GPU 영상 인코딩 오프로드 spec + plan
NAS 저성능 CPU(J4025) ffmpeg 5분 타임아웃 → Windows PC RTX 5070 Ti NVENC로
오프로드. 같은 music_ai 서버에 /encode_video endpoint 추가, NAS는 다운 시
즉시 실패 (로컬 폴백 X). LAN 무인증.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 01:52:34 +09:00
47e5315487 fix(music-lab): ffmpeg 인코딩 가속 + 타임아웃 확장 (저성능 CPU 대응)
- preset fast → ultrafast (5-10x 가속, J4025 같은 저성능 CPU에서 5분 내 완료)
- tune stillimage 추가 (정적 배경 + 파형 오버레이에 최적)
- threads 0 — 모든 CPU 코어 활용
- VIDEO_TIMEOUT_S 300 → 600 (안전 마진)
- subprocess.TimeoutExpired 캐치하여 명확한 에러 메시지
2026-05-09 01:01:03 +09:00
97b15cb985 fix(pipeline): premature state update + reject 재생성 알림
버그1: /feedback approve가 bg task 시작 전에 state를 next_pending으로 set →
polling이 빈 video_url로 알림 발송. bg task의 run_step이 state를 set하도록
일임 — 이중 update 제거.

버그2: reject 후 같은 *_pending 상태로 재생성됐을 때 dedupe에 막혀 알림이
안 감. dedupe 키에 feedback_count_per_step[step]을 포함 — 재생성마다
count가 증가하므로 키가 달라져 재알림 동작.
2026-05-08 23:08:24 +09:00
6d416aab78 fix(music-lab): pipeline 동기 작업을 asyncio.to_thread로 — 이벤트 루프 블로킹 해결
video.generate/thumb.generate/youtube.upload_video는 동기 함수로 ffmpeg subprocess(최대 5분)와
google-api-python-client(최대 10분)를 호출함. async run_step에서 직접 호출하면 이벤트 루프가
블로킹돼 후속 요청이 504로 타임아웃되고 텔레그램 폴링도 끊김.

asyncio.to_thread로 감싸 스레드 풀에서 실행 — 이벤트 루프 자유.
2026-05-08 22:57:33 +09:00
2c13e7cc85 fix(music-lab): pipeline 오디오 경로 + ffmpeg 에러 가시성
- orchestrator._run_video: track.file_path 우선 사용 (audio_url 변환 불필요)
- _local_path: /media/music/ → /app/data/ (마운트가 /app/data 직접이라 music 서브디렉토리 없음)
- video.py/thumb.py: stderr truncation [-800:]/[-500:] — 진짜 에러 보이게
2026-05-08 22:50:13 +09:00
4f67cd02fa fix(music-lab): pipeline 응답에 track_title 포함 (LEFT JOIN music_library) 2026-05-07 17:43:55 +09:00
868906b8c6 test(music-lab): 풀 파이프라인 통합 테스트 (mock) 2026-05-07 17:37:15 +09:00
bd97cc1e97 chore(infra): pipeline env (OPENAI/YOUTUBE_OAUTH_*) + 폰트
music-lab 서비스에 OpenAI/YouTube OAuth 환경변수 + Claude 모델 변수 추가.
agent-office에도 CLAUDE_HAIKU_MODEL/CLAUDE_SONNET_MODEL 노출.
Alpine 기반 music-lab 이미지에 ttf-dejavu + fontconfig 설치하고
PIL이 참조하는 Debian 스타일 경로(/usr/share/fonts/truetype/dejavu)로
심볼릭 링크 생성하여 썸네일/그라디언트 폰트 로딩 보장.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 17:33:44 +09:00
7552ce4263 feat(agent-office): youtube_publisher 에이전트 + 30s 폴링
- YoutubePublisherAgent: 음악 파이프라인의 *_pending 상태를 폴링하여
  텔레그램 단일 채널로 단계별 검토 요청 발송, reply 수신 시 의도 분류
  후 music-lab에 feedback POST
- service_proxy: pipeline list/get/feedback/telegram-msg/lookup-by-msg
  헬퍼 5종 추가 (MUSIC_LAB_URL 사용)
- scheduler: 30초 interval로 poll_state_changes 실행
- telegram webhook: reply_to_message 가 파이프라인 메시지면
  youtube_publisher 로 라우팅 (슬래시 명령보다 우선)
- 테스트 4종 추가 (4 PASS)
2026-05-07 17:20:21 +09:00
17034ea6ea feat(agent-office): 텔레그램 자연어 의도 분류 2026-05-07 17:15:24 +09:00
fe60c8d330 feat(music-lab): pipeline 오케스트레이터 + 14 엔드포인트 2026-05-07 17:11:29 +09:00
4755e34c14 feat(music-lab): YouTube OAuth + resumable 업로드 2026-05-07 17:05:12 +09:00
ad1c721ba8 feat(music-lab): pipeline 4축 AI 검토 + 휴리스틱 폴백 2026-05-07 17:01:17 +09:00
1c705b0ef3 feat(music-lab): pipeline 메타데이터 LLM 생성 + 폴백 2026-05-07 16:58:03 +09:00
68dec2e53d feat(music-lab): pipeline 영상·썸네일 생성 2026-05-07 16:53:57 +09:00
e33a2310af feat(music-lab): AI 커버 생성 + 그라데이션 폴백
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:50:28 +09:00
fceca88db4 feat(music-lab): pipeline 상태 머신 2026-05-07 16:40:31 +09:00
d66a321982 feat(music-lab): pipeline 5개 DB 테이블 + 헬퍼
YouTube 음악 파이프라인 Task 1 — 신규 5개 테이블과 헬퍼 함수 추가.

테이블:
- video_pipelines: 파이프라인 단위 상태 머신 + 메타/리뷰 JSON
- pipeline_jobs: 단계별 비동기 작업 상태/시간
- pipeline_feedback: 텔레그램 피드백 이력
- youtube_oauth_tokens: 채널 OAuth refresh/access 토큰
- youtube_setup: 단일 행 설정 (메타 템플릿/커버 프롬프트/리뷰 가중치/임계값/비주얼/공개정책)

헬퍼:
- create_pipeline / get_pipeline / update_pipeline_state / list_pipelines
- increment_feedback_count / record_feedback / get_feedback_history
- create_pipeline_job / update_pipeline_job / list_pipeline_jobs
- get_youtube_setup / update_youtube_setup
- upsert_oauth_token / get_oauth_token / delete_oauth_token

테스트:
- tests/test_pipeline_db.py: 7개 테스트 (생성/상태/피드백/잡/셋업/OAuth)
- tests/conftest.py: freezegun 기반 freezer fixture 추가
- requirements.txt: freezegun>=1.4 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:37:11 +09:00
e03d074222 docs(plan): Music YouTube 파이프라인 구현 계획 — 16 task
스펙 2026-05-07-music-youtube-pipeline-design.md를 16개 task로 분해.
TDD 패턴: 각 task = 실패 테스트 → 구현 → 통과 → 커밋.

태스크 흐름:
1. DB 5개 테이블 + 헬퍼
2. 상태 머신
3. Storage + 커버 (DALL·E + 폴백)
4. 영상/썸네일 (FFmpeg)
5. 메타데이터 (Claude Haiku)
6. AI 검토 4축 (Claude Sonnet + 휴리스틱)
7. YouTube OAuth + 업로드
8. 오케스트레이터 + 13 엔드포인트
9. agent-office 자연어 의도 분류
10. youtube_publisher 에이전트 + 30s 폴링
11. web-ui api.js 헬퍼
12. SetupTab
13. PipelineTab + 카드
14. YoutubeTab 6 서브탭 + Library 트리거
15. docker-compose env + nginx
16. 통합 테스트 + 수동 E2E

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:23:46 +09:00
2eeb98a723 docs(spec): Music YouTube 파이프라인 단계별 승인 자동화 설계
트랙 → 영상 → 발행까지 단계별 텔레그램 승인 워크플로 설계.
- 6단계 진행 바: 커버/영상/썸네/메타/AI검토/발행
- 자연어 의도 분류 (화이트리스트 + LLM 폴백)
- 반려 시 사용자 피드백 반영 재생성 (5회 한도)
- AI 최종 검토 4축 가중평균 (메타/정책/시청/트렌드)
- music-lab 5개 신규 테이블 + 12개 엔드포인트
- agent-office youtube_publisher 에이전트 + scheduler 폴링
- web-ui SetupTab + PipelineTab 신규 + Library 트리거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:13:29 +09:00
657ffdc55f fix(agent-office): 아침 브리핑 직전 뉴스 스크랩 트리거 — 어제 뉴스 송출 방지
기존: stock-lab cron 스크랩(08:00)이 stock 에이전트 브리핑(07:30)보다 늦어
어제 8시 스크랩 결과만 DB에 있어 어제 뉴스가 요약·전송되었음.

수정: 에이전트 on_schedule에서 summarize 직전 /api/stock/scrap을 호출해
DB를 오늘 새벽 뉴스로 갱신한 뒤 요약. 스크랩 실패 시 경고 로그만 남기고
이전 데이터로 진행(브리핑 자체가 무산되는 것은 방지).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:31:55 +09:00
f54da7d46a chore(harness): 프로젝트 settings.json — git/docker/pytest allowlist + 민감파일 deny
체크인되는 프로젝트 권한 설정. read-only 명령(status/diff/logs/ps 등)을
사전 승인하여 권한 프롬프트 감소. .env / *.pem / *.key / lotto.db / stock.db
deny로 비밀·DB 직접 읽기 차단.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:06:12 +09:00
dc92c3d42d docs: 완료된 spec/plan 제거 + lotto 프리미엄 로드맵 보존
운영 중인 기능에 대한 design/plan 문서 일괄 삭제(20개 spec + 14개 plan).
미구현 pet-lab만 보존. lotto-premium-roadmap.md 신규 추가
(Phase 3 구독 모델 미구현 — STATUS.md에서 참조).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:06:04 +09:00
24a57f2b69 docs: STATUS.md — 서비스 현황 + 향후 계획 정리
10개 컨테이너 운영 상태와 Phase별 향후 작업 인덱스. CLAUDE.md를 보완.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 14:57:28 +09:00
b9d3242341 Merge branch 'feat/packs-lab-infra'
packs-lab 인프라 통합 + admin mint-token 구현 — 9 task TDD

- conftest.py로 테스트 HMAC secret 통일
- POST /api/packs/admin/mint-token 라우트 (Vercel HMAC → 일회성 upload 토큰)
- 기존 4 라우트 회귀 테스트 + DSM client mock 테스트
- Supabase pack_files DDL + 활성/삭제 인덱스
- docker-compose 18950 + nginx /api/packs/ 5GB streaming + env 8개
- PACK_BASE_DIR 환경변수화 (마운트 경로와 정합성 확보)
- web-backend CLAUDE.md 5곳 + workspace CLAUDE.md 1줄 갱신
- 24 tests passing
2026-05-06 03:35:37 +09:00
5e9a51c9e8 docs(claude): packs-lab 10번째 서비스로 등록 (포트/라우팅/API 표 + 신규 섹션)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:42:15 +09:00
5844567048 fix(packs-lab): PACK_BASE_DIR을 환경변수로 — 컨테이너 마운트 경로와 routes 정합성 확보
이전 docker-compose는 컨테이너 내부 /app/data/packs로 마운트하지만 routes.py는
/volume1/docker/webpage/media/packs를 하드코딩하고 있어 mismatch였다.

- routes.py: PACK_BASE_DIR = Path(os.getenv("PACK_BASE_DIR", "/app/data/packs"))
- docker-compose: PACK_BASE_DIR env 추가 + volume 마운트가 같은 경로 사용
- .env.example: PACK_BASE_DIR 신규 명시 (마운트 경로와 반드시 일치 안내)
2026-05-06 01:40:07 +09:00
0906c3ba35 chore(infra): packs-lab 서비스 통합 (compose 18950 + nginx 5GB streaming + env 7개)
- docker-compose.yml: 포트 18910→18950 수정, env 형식을 list 스타일로 통일,
  TZ/UPLOAD_TOKEN_TTL_SEC 추가, volume 경로를 /app/data/packs으로 정정
- .env.example: packs-lab 섹션 신규 추가 (DSM_HOST/DSM_USER/DSM_PASS/
  BACKEND_HMAC_SECRET/SUPABASE_URL/SUPABASE_SERVICE_KEY/UPLOAD_TOKEN_TTL_SEC/PACK_DATA_PATH)
- nginx/default.conf: 이전 커밋(9a0bbec)에 이미 포함 — 변경 없음

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:37:29 +09:00
ff4ef299ad feat(packs-lab): Supabase pack_files DDL + 활성/삭제 인덱스 2026-05-06 01:35:19 +09:00
5ebcbae8b5 docs(packs-lab): routes 모듈 docstring 정리 (mint-token 추가, DSM 자동 만료 명시) 2026-05-06 01:34:47 +09:00
1cd3cf8830 test(packs-lab): DSM client mock 테스트 (login/share/logout 순서)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:33:11 +09:00
c18fd8e52b test(packs-lab): upload size/replay + delete soft-delete + list filter 회귀 테스트
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:30:46 +09:00
dc482b32e4 feat(packs-lab): POST /api/packs/admin/mint-token 라우트 + 통합 테스트
MintTokenRequest/Response 스키마 추가, mint_token 라우트 구현 (HMAC 인증 + 확장자 검증 + JTI 발급), 테스트 3건 추가.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:27:43 +09:00
ef026e7ac6 test(packs-lab): conftest로 HMAC secret 통일
모든 테스트에서 BACKEND_HMAC_SECRET 환경변수와 auth._SECRET 모듈 캐시를
동일한 값으로 설정하는 autouse fixture 추가.
기존 test_auth.py / test_routes.py와 동일한 secret 값 사용.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 01:24:17 +09:00