Compare commits
4 Commits
feat/insta
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c8684280af | |||
| 6895e2f8dc | |||
| 34619dc70b | |||
| 47cdc43aa5 |
@@ -102,8 +102,16 @@ def _build_mapping(pngs: List[str]) -> Dict[str, int]:
|
|||||||
return mapping
|
return mapping
|
||||||
|
|
||||||
|
|
||||||
|
_EXPECTED_RATIO = 1080 / 1350 # 4:5 = 0.8
|
||||||
|
_RATIO_TOLERANCE = 0.02 # ±2% (1122/1402 ≈ 0.80028도 통과)
|
||||||
|
|
||||||
|
|
||||||
def _validate_images(pages_dir: Path) -> None:
|
def _validate_images(pages_dir: Path) -> None:
|
||||||
"""모든 PNG가 정확히 1080×1350인지 검증. 다르면 ValueError.
|
"""모든 PNG가 4:5 종횡비(1080x1350 권장)에 가까운지 검증.
|
||||||
|
|
||||||
|
Vision은 base64로 원본을 분석하고 Playwright는 background-size: cover로
|
||||||
|
1080x1350 컨테이너에 fit하므로 절대 사이즈는 유연. 단 종횡비가 어긋나면
|
||||||
|
카드가 늘어나거나 잘리므로 ±2% 허용 범위 내에서만 통과.
|
||||||
|
|
||||||
early-exit 하지 않고 전체 파일을 검사한 뒤 한 메시지에 모아 raise.
|
early-exit 하지 않고 전체 파일을 검사한 뒤 한 메시지에 모아 raise.
|
||||||
"""
|
"""
|
||||||
@@ -111,12 +119,17 @@ def _validate_images(pages_dir: Path) -> None:
|
|||||||
bad = []
|
bad = []
|
||||||
for png_path in sorted(pages_dir.glob("*.png")):
|
for png_path in sorted(pages_dir.glob("*.png")):
|
||||||
with Image.open(png_path) as img:
|
with Image.open(png_path) as img:
|
||||||
if img.size != _EXPECTED_SIZE:
|
w, h = img.size
|
||||||
|
if h == 0:
|
||||||
|
bad.append((png_path.name, img.size))
|
||||||
|
continue
|
||||||
|
ratio = w / h
|
||||||
|
if abs(ratio - _EXPECTED_RATIO) > _RATIO_TOLERANCE:
|
||||||
bad.append((png_path.name, img.size))
|
bad.append((png_path.name, img.size))
|
||||||
if bad:
|
if bad:
|
||||||
msg = "; ".join(f"{n}: {s[0]}x{s[1]}" for n, s in bad)
|
msg = "; ".join(f"{n}: {s[0]}x{s[1]}" for n, s in bad)
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"모든 카드 디자인은 1080x1350이어야 함. 잘못된 파일: {msg}"
|
f"카드 디자인은 4:5 비율(1080x1350 권장)이어야 함. 잘못된 파일: {msg}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
12
insta-lab/app/templates/minimal/pages/_order.json
Normal file
12
insta-lab/app/templates/minimal/pages/_order.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"insta_card_start.png": 1,
|
||||||
|
"insta_card_keyword.png": 2,
|
||||||
|
"insta_card_highlight.png": 3,
|
||||||
|
"insta_card_observation.png": 4,
|
||||||
|
"insta_card_memo.png": 5,
|
||||||
|
"insta_card_oneline.png": 6,
|
||||||
|
"insta_card_checklist.png": 7,
|
||||||
|
"insta_card_study.png": 8,
|
||||||
|
"insta_card_cta.png": 9,
|
||||||
|
"insta_card_finish.png": 10
|
||||||
|
}
|
||||||
@@ -5,5 +5,6 @@ httpx>=0.27
|
|||||||
anthropic==0.52.0
|
anthropic==0.52.0
|
||||||
jinja2>=3.1.4
|
jinja2>=3.1.4
|
||||||
playwright==1.48.0
|
playwright==1.48.0
|
||||||
|
Pillow>=10
|
||||||
pytest>=8.0
|
pytest>=8.0
|
||||||
pytest-asyncio>=0.24
|
pytest-asyncio>=0.24
|
||||||
|
|||||||
@@ -86,6 +86,14 @@ def _make_png(path: Path, size: tuple[int, int]) -> None:
|
|||||||
Image.new("RGB", size, color=(200, 200, 200)).save(path, format="PNG")
|
Image.new("RGB", size, color=(200, 200, 200)).save(path, format="PNG")
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_images_accepts_higher_resolution_4_5_ratio(tmp_theme):
|
||||||
|
"""1080x1350 외에도 같은 4:5 비율이면 통과 (예: 1122x1402, 디자인 도구 export 흔한 사이즈)."""
|
||||||
|
pages = tmp_theme / "pages"
|
||||||
|
for i in range(10):
|
||||||
|
_make_png(pages / f"insta_card_{i:02d}.png", (1122, 1402))
|
||||||
|
design_importer._validate_images(pages) # 예외 없으면 통과
|
||||||
|
|
||||||
|
|
||||||
def test_validate_images_accepts_1080x1350(tmp_theme):
|
def test_validate_images_accepts_1080x1350(tmp_theme):
|
||||||
pages = tmp_theme / "pages"
|
pages = tmp_theme / "pages"
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
|
|||||||
Reference in New Issue
Block a user