feat: 블로그 대표 이미지 자동 삽입 (Pexels/Unsplash)
- 발행 시 본문에 <img>가 없으면 자동으로 대표 이미지 추가 - Pexels API (PEXELS_API_KEY 있을 때) → Unsplash Source (무료 폴백) - 글 태그/코너 기반 키워드로 관련 이미지 검색 - Blogger가 첫 번째 <img>를 자동으로 thumbnail로 사용 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -206,12 +206,59 @@ def build_json_ld(article: dict, blog_url: str = '') -> str:
|
||||
return f'<script type="application/ld+json">\n{json.dumps(schema, ensure_ascii=False, indent=2)}\n</script>'
|
||||
|
||||
|
||||
def fetch_featured_image(article: dict) -> str:
|
||||
"""글 키워드 기반 무료 대표 이미지 URL 가져오기 (Pexels → Unsplash fallback)"""
|
||||
# 검색 키워드: 태그 또는 코너 기반
|
||||
tags = article.get('tags', [])
|
||||
if isinstance(tags, str):
|
||||
tags = [t.strip() for t in tags.split(',')]
|
||||
corner = article.get('corner', '')
|
||||
query = tags[0] if tags else corner or 'technology'
|
||||
|
||||
# Pexels API (키가 있을 때)
|
||||
pexels_key = os.getenv('PEXELS_API_KEY', '')
|
||||
if pexels_key:
|
||||
try:
|
||||
resp = requests.get(
|
||||
'https://api.pexels.com/v1/search',
|
||||
headers={'Authorization': pexels_key},
|
||||
params={'query': query, 'per_page': 1, 'orientation': 'landscape'},
|
||||
timeout=10,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
photos = resp.json().get('photos', [])
|
||||
if photos:
|
||||
return photos[0]['src']['large']
|
||||
except Exception as e:
|
||||
logger.warning(f"Pexels 이미지 검색 실패: {e}")
|
||||
|
||||
# Unsplash Source (API 키 불필요, 직접 URL)
|
||||
import urllib.parse
|
||||
encoded = urllib.parse.quote(query)
|
||||
return f'https://source.unsplash.com/1200x630/?{encoded}'
|
||||
|
||||
|
||||
def build_full_html(article: dict, body_html: str, toc_html: str) -> str:
|
||||
"""최종 HTML 조합: JSON-LD + 목차 + 본문 + 면책 문구"""
|
||||
"""최종 HTML 조합: 대표이미지 + JSON-LD + 목차 + 본문 + 면책 문구"""
|
||||
json_ld = build_json_ld(article)
|
||||
disclaimer = article.get('disclaimer', '')
|
||||
|
||||
html_parts = [json_ld]
|
||||
# 본문에 이미 <img> 태그가 있으면 대표 이미지 삽입 건너뜀
|
||||
has_image = '<img ' in body_html.lower()
|
||||
|
||||
html_parts = []
|
||||
if not has_image:
|
||||
image_url = fetch_featured_image(article)
|
||||
if image_url:
|
||||
title = article.get('title', '')
|
||||
html_parts.append(
|
||||
f'<div class="featured-image" style="margin-bottom:1.5em;">'
|
||||
f'<img src="{image_url}" alt="{title}" '
|
||||
f'style="width:100%;max-height:400px;object-fit:cover;border-radius:8px;" />'
|
||||
f'</div>'
|
||||
)
|
||||
|
||||
html_parts.append(json_ld)
|
||||
if toc_html:
|
||||
html_parts.append(f'<div class="toc-wrapper">{toc_html}</div>')
|
||||
html_parts.append(body_html)
|
||||
|
||||
Reference in New Issue
Block a user