지난 화요일에 저는 업로드 배치 작업을 두 번 실행했습니다. 동일한 폴더, 동일한 CSV 파일이었고, 두 시간 간격으로 진행되었는데, 제가 이미 Adobe에 푸시했던 40개의 파일 중 어떤 것을 했는지 기억나지 않았기 때문입니다. Adobe는 실수로 인한 중복 파일을 경고와 함께 처벌하지 않습니다. 대신 이는 검토 등급(review standing)에 영향을 미치며, 이미 게시된 자산을 반복적으로 재제출하는 것은 리뷰어들이 기여자 계정을 플래그 지정하는 이유 중 하나로 명시되어 있습니다. 저는 두 번째 배치가 진행되기 전에 이를 발견했는데, 업로드 기록을 열고 스크롤했기 덕분이었습니다. 그때 제가 추적 관리가 기억이 아니라 스크립트로 되어야겠다고 결심했습니다.
제가 배운 솔직한 내용과 현재 일주일에 한 번씩 운영하는 시스템은 다음과 같습니다.
CSV 헤더는 제안이 아닌 필수 조건입니다
세 개의 주요 스톡 채널 모두 잘못된 헤더를 가진 메타데이터 파일은 즉시 거부합니다. 부드러운 경고가 아니라, 업로드 단계에서 거부되는 것입니다. Adobe는 5개 열 형식을 기대하고, Vecteezy는 4개 열을 기대하며, Dreamstime은 15개를 원합니다. 만약 이들을 스프레드시트에서 직접 만들 경우, 결국 열 순서를 잘못 지정하거나 구분 기호(delimiter)를 잘못 저장하게 되어 전체 배치가 실패할 것입니다.
그래서 make_metadata.py는 각 플랫폼이 요구하는 정확한 헤더만 작성하고 그 외의 것은 아무것도 쓰지 않습니다. 이 스크립트에 파일 폴더를 지정하고, 플랫폼을 선택하면 첫 번째 검사를 통과하는 CSV 파일을 얻게 됩니다. 또한 백업 기능도 있습니다. 만약 제목 파일(titles file)을 제공하지 않으면, 파일 이름을 title-case로 변환해 줍니다. 이는 첫 번째 시도에는 괜찮지만, 리뷰어들이 읽기 때문에 제출하기 전에 저는 이 제목들을 교체합니다.
스프레드시트를 수동으로 편집하는 것을 멈추면서 시간 계산이 달라졌습니다. 40개 자산 배치에 대한 세 개의 플랫폼 CSV를 만드는 것은 예전에는 저녁 대부분을 차지했습니다. 이제는 단지 세 개의 명령어와 약 1분의 컴퓨팅 시간이 걸립니다.
중복 게시(Double-posting)는 플래그가 지정되는 가장 빠른 방법입니다
이 부분은 제가 운이 좋았던 경우입니다. 동일한 채널에 대해 배치를 두 번 실행하는 것은 업로드를 자동화하는 사람이라면 누구나 저지르는 전형적인 실수입니다. 스톡 사이트들은 중복 제출을 품질 문제로 취급하며, 충분히 많이 발생하면 계정이 검토되거나 제한될 수 있습니다.
제 해결책은 매우 단순해서 작동합니다. upload_tracker.py는 평범한 원장(ledger)입니다. 배치 작업을 실행하기 전에 pending 상태인 항목들을 제 아이템 파일과 비교하여 완료되지 않은 것을 확인합니다. 성공적인 업로드 후에는 해당 항목을 done으로 표시합니다. 이 원장은 제가 읽고, 백업하고, grep 할 수 있는 텍스트 파일입니다. 배치를 재실행하는 스크립트는 먼저 이 원장을 확인하므로 중복 게시가 어려울 뿐만 아니라 불가능합니다.
이런 시스템을 구축하는 모든 사람에게 주는 교훈은 이것입니다: 데이터베이스를 만들지 마세요. 오해할 수 없는 목록(list)을 만드세요. 저의 전체 업로드 기록은 메모장으로 열어볼 수 있는 단 하나의 파일입니다.
2GB 박스에서 한 번에 하나의 프로세스 처리하기
전체 파이프라인은 vCPU 1개, RAM 2GB, GPU 없이 실행됩니다. 이 제약 조건이 시스템의 모든 습관을 형성했습니다.
단일 코어에서 이미지 작업을 병렬로 분산(fan out)하지 마세요. 속도가 빨라지지 않고, 오히려 느려지고 박스가 무너집니다. 저는 각 에셋 처리 후에 gc.collect()를 호출하여 항목들 사이에 메모리를 확보합니다. 무거운 렌더링 단계의 경우, 메모리가 파이썬 내부에서 풀(pool)되는 대신 OS로 실제로 반환되도록 서브프로세스당 파일 하나씩을 처리합니다. 그리고 평균값 대신 최대 RSS(resource.getrusage(RUSAGE_SELF).ru_maxrss)를 측정하는데, 그 이유는 평균값으로는 작업이 실패하는 순간에 대한 아무것도 알려주지 않기 때문입니다.
실제 돈을 절약해 준 또 다른 점은: 필요한 해상도에서 렌더링 하세요. 300dpi 대신 60dpi로 미리보기를 검사하는 것은 비용이 거의 들지 않으며, 최종 출력에 대해서만 전체 해상도를 지불합니다. AI 이미지 생성은 이미지당 가격이 책정되므로, 고해상도에서 검사가 실패했다고 해서 전체 배치를 재렌더링 하는 것은 이론적인 비용이 아니라 실제 비용입니다.
패키징은 기술(craft)이 아닌 명령어이다
맨 파일로는 팔 수 없습니다. 1280x720의 실제 커버와 600x600의 썸네일이 포함된 zip 파일이 팔립니다. 저는 예전에 이미지 편집기에서 제품당 30분에서 45분을 커버 제작에 사용했고, 이는 39개 제품의 경우 저녁 시간을 할애하여 일주일 전체가 소요되는 시간이었습니다.
pack_product.py는 폴더, 제목, 부제목, 항목 개수를 입력받아 zip 파일, 커버 이미지, 썸네일을 작성합니다. 사용된 외부 패키지는 Pillow가 유일합니다. 커버 이미지는 예술 작품이 아니라 일관된 프레임워크이며, 이러한 일관성은 스크립트가 가장 잘하는 부분입니다.
문서도 마찬가지입니다. md2pdf.py는 reportlab을 사용하여 마크다운(Markdown) 파일을 제목, 표, 목록, 링크가 포함된 스타일이 적용된 PDF로 변환합니다. 단 하나의 명령으로 처리됩니다. 문서들이 제품처럼 보이는 이유는 제가 밤 11시에 취향이 좋아서가 아니라, 스타일링이 고정되어 있기 때문입니다.
폴더 구조가 도구보다 더 중요하다
고정된 구조가 없다면 카탈로그는 잡동사니 서랍장이 됩니다. 제 시스템은 다섯 개의 폴더로 구성됩니다: 원본 결과물용 assets, 제출 준비 완료 파일 및 메타데이터용 output, 완성된 zip 파일과 커버 이미지용 packs, 메모와 크롤링 로그용 research, 그리고 도구용 scripts입니다.
제가 초기에 실수했던 점은, 정리 과정에서 research 폴더를 삭제했다는 것입니다. 그 노트와 로그들은 미래 제품을 위한 원자재입니다. 저는 복구할 수 있는 것을 재구축했고, 이제 이 폴더의 어떤 내용도 제거되지 않도록 했습니다.
현재 일주일이 실제로 어떻게 돌아가는가
어느 저녁, 대략 3시간 정도 걸립니다. 그 주간의 에셋을 생성하고 검토하며, 세 가지 메타데이터 명령어를 실행하고, pending으로 레저를 확인한 다음, 제품 두세 개를 패키징하고 모든 것을 완료로 표시합니다. 이 스크립트들은 지금까지 총 39개의 제품을 패키징했으며, 약 856 MB의 결과물을 생성했고, 이는 모두 2 GB 서버에서 이루어졌습니다. 전체 상위 파이프라인은 약 19,000줄에 달하지만, 매일 필요한 패키징 레이어는 네 개의 스크립트와 두 개의 pip 설치만 필요합니다.
제가 이것을 자동화된 사업이라고 포장할 생각은 없습니다. 검토자들은 여전히 거절하는 것이 있고, 제목은 여전히 수정이 필요하며, 어떤 주에는 저녁 시간을 아예 건너뛰기도 합니다. 하지만 지난 화요일에 제가 깜빡해서 배치 작업을 두 번 실행했던 실패 모드는 이제 구조적으로 불가능해졌습니다.
저는 이 네 개의 스크립트, 폴더 구조, 그리고 RAM 노트를 파이프라인 스타터 키트로 묶었습니다. 왜냐하면 패키징 레이어는 모든 사람을 지치게 만드는 지루한 부분이고, 이것을 제대로 하는 데 일 년이 걸려서는 안 되기 때문입니다.
Get pipeline starter kit
디지털 제품을 구축하고 계신가요? 디지털 제품 판매자를 위한 무료 가이드 및 키트.