저는 아직도 거절 이메일을 탭으로 열어두고 있습니다. 64개의 에셋, 주말 내내 걸린 렌더링 작업이 Adobe Stock에 의해 통째로 무효 처리되었습니다. 그 이유는 제 CSV 파일의 헤더 행에 5개가 아닌 6개 열을 포함했기 때문입니다. 부분 승인도, 경고도 없었습니다. 단순히 업로드만 실패했고, 저는 이미 완성되어 쓸모없게 놓여 있는 이미지들로부터 메타데이터를 처음부터 다시 구축해야 했습니다.
이 경험을 통해 '수동으로 처리할게'라는 믿음을 버리고 대신 네 개의 작은 Python 스크립트를 작성하게 되었습니다. 이 스크립트들은 GPU나 클라우드 계정 없이, 1 vCPU, 2 GB RAM 서버에서 실행되었고, 약 856 MB의 결과물을 포함한 39개의 완성된 제품을 패키징했습니다. 각 스크립트가 무엇을 하는지, 그리고 이 스크립트들이 해결하는 문제가 얼마나 현실적인지 설명드리겠습니다.
메타데이터는 작성 문제가 아니라 형식 문제입니다
주요 세 플랫폼 모두 파일 자체를 보기 전에 CSV 헤더를 검증합니다. Adobe는 5개 열을 원하고, Vecteezy는 4개를 원하며, Dreamstime은 15개를 원합니다. 단 하나의 열만 잘못해도 업로드가 즉시 거부되며, 이는 제가 겪었던 방식과 동일했습니다.
그래서 make_metadata.py는 각 플랫폼이 요구하는 정확한 헤더와 그 외 아무것도 쓰지 않습니다. 이 스크립트를 폴더를 가리키게 하면 됩니다:
python make_metadata.py ./my-assets --platform adobe --out metadata.csv --ext .jpg
이 스크립트는 폴더를 순회하며 파일 이름을 제목 케이스(title-case)로 변환하여 제목으로 사용하고 CSV를 생성합니다. 만약 실제 제목과 키워드가 있다면, --titles titles.json을 전달하면 그것들을 대신 사용합니다. 파일 이름으로 대체하는 방식은 첫 번째 시도에는 괜찮지만, 제출하기 전에 반드시 교체해야 합니다. 'Asset 001 Final V2'와 같은 제목은 검토자에게 자동화된 작업처럼 보일 수 있으며, 검토자들은 자동화된 것처럼 보이는 것을 거부합니다.
이 스크립트와 트래커는 Python 표준 라이브러리만을 사용합니다. pip install이나 의존성(dependencies) 문제로 고장 날 일이 없습니다.
중복 업로드는 플래그를 받는 가장 빠른 방법입니다
초기에 제가 이미 올라간 것을 파악하지 못하고 한 배치(batch)를 두 번 실행한 적이 있습니다. 이것이 전형적인 실수입니다. 동일한 파일을 여러 계정이나 중복으로 재제출하는 것은 플랫폼 검토 시스템에 스팸처럼 보이며, 귀하의 계정을 위험에 빠뜨립니다.
upload_tracker.py는 단순한 원장(ledger)입니다. 업로드하기 전에 다음을 확인합니다:
python upload_tracker.py pending items.txt
python upload_tracker.py done "asset-001.jpg"
python upload_tracker.py status
다시 실행하면 아직 완료되지 않은 항목이 무엇인지 정확히 보여줍니다. 영리하지 않습니다. 몇 가지 명령어가 주변에 있는 텍스트 파일일 뿐이며, 그것이 요점입니다. 영리한 시스템은 작은 서버에서 조용히 실패합니다. 원장은 그렇지 않습니다.
문서를 제품처럼 보이게 변환하기
마크다운(Markdown) 파일 안에 정말 좋은 콘텐츠가 있어도, 날것의 .md 파일 자체는 제품이 아니기 때문에 판매할 만한 것이 없을 수 있습니다. md2pdf.py는 하나의 마크다운 파일을 받아 제목, 표, 목록 및 작동하는 링크가 포함된 스타일리시한 PDF로 렌더링합니다:
python md2pdf.py content.md product.pdf "내 제품 제목"
이 스크립트는 reportlab을 사용하는데, 이는 이 전체 파이프라인에서 유일하게 세 번째 외부 패키지입니다. 다른 하나는 Pillow입니다. 나머지 모든 것은 표준 라이브러리입니다. 저는 의도적으로 종속성(dependency) 개수를 두 개로 유지했는데, 왜냐하면 추가적인 패키지는 감시하는 사람이 없는 2GB짜리 박스에서 고장 날 수 있는 또 다른 요소이기 때문입니다.
커버가 있는 zip은 팔리고, 맨 파일은 안 팔린다
마지막 단계는 패키징이며, 예상보다 더 중요합니다. 실제 크기 1280×720의 커버와 600×600의 썸네일이 포함된 zip 파일은 상점에서 등록해야 할 것 같은 느낌을 줍니다. 맨 파일만 있는 zip은 다운로드 실수처럼 보입니다.
pack_product.py는 하나의 명령으로 이 두 가지를 모두 수행합니다:
python pack_product.py my-product "내 제품" "짧은 부제목" 9
이 스크립트는 _system 폴더 안에 zip, 커버, 썸네일을 작성합니다. --dir 또는 PACK_ROOT 환경 변수를 사용하여 출력을 리디렉션할 수 있으므로, 스크립트를 편집할 필요가 없습니다. Pillow가 이미지를 렌더링하는데, 이는 단일 코어에서 스와핑 없이 하나씩 실행하기에 충분히 저렴합니다.
이것이 작동하게 만든 소형 서버 습관들
이 스크립트들 중 어느 것도 무겁지는 않지만, 주변의 렌더링 단계들은 무거웠고, 2GB라는 제한은 복사할 가치가 있는 습관들을 강요했습니다:
- 한 번에 하나의 프로세스로 처리하세요. 1코어 환경에서 이미지 작업을 병렬로 분산(fan out)하지 마세요.
- 각 에셋 처리 후
gc.collect()를 호출하여 메모리가 실제로 해제되도록 하세요.
- 평균값 대신 최대 RSS(Resident Set Size)를 측정하세요.
resource.getrusage(RUSAGE_SELF).ru_maxrss가 프로세스가 도달하는 실제 최고치를 알려줍니다.
- 무거운 렌더링 단계는 서브프로세스별로 하나의 파일로 실행하여 메모리가 OS로 반환되게 하세요.
- 300dpi로 렌더링하는 대신 60dpi에서 미리보기를 검사하세요. 최종 파일에만 전체 해상도가 필요합니다.
이 모든 과정은 부모 프로젝트의 약 19,000줄 분량의 파이프라인 코드와 이 스크립트들이 강제하는 규칙 뒤에 있는 약 300페이지 분량의 연구 자료를 기반으로 작동했습니다. 스크립트 자체는 작습니다. 하지만 그 안에 담긴 규칙들은 그렇지 않습니다.
어디서 얻을 수 있나요
저는 이 네 가지 스크립트, 제가 사용하는 폴더 구조(assets, output, packs, research, scripts), 그리고 설치 및 빠른 시작 명령어를 'Pipeline Starter Kit'이라는 패키지로 묶었습니다. 이는 월 $0인 로컬 오케스트레이터(스케줄링 및 재시도용)와 로컬 LLM 프록시라는 무료 스택 아래에 자리 잡고 있습니다. 이 키트는 완성된 파일을 목록화된 제품으로 변환하는 '패키징 계층'입니다.
이것은 그 39개 제품을 패키징했던 것과 동일한 도구이며, 단순히 정리하여 다시 작성한 것이 아닙니다. 만약 에셋 작업이 완료되었고 메타데이터 CSV 파일만이 사용자님과 업로드 사이에 놓여 있는 단계라면, 바로 이 문제에 맞춰 만들어진 것입니다.
아트적인 측면도 원한다면, 벡터 프롬프트 팩(vector prompt pack)은 애초에 이 파이프라인을 구동했던 '프롬프트 엔진'입니다.
벡터 프롬프트 팩 받기
디지털 제품 제작 중이신가요? 디지털 제품 판매자를 위한 무료 가이드 및 키트.