chore: 停止上传开发文档并同步代码
- 从仓库索引移除 开发文档/(本地保留) - 忽略 wechat/info.log 与 soul-api-linux - 同步小程序/管理端/API改动 Made-with: Cursor
This commit is contained in:
@@ -32,12 +32,12 @@ except ImportError:
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
# 默认发到 Soul 彩民团队飞书群
|
||||
WEBHOOK = "https://open.feishu.cn/open-apis/bot/v2/hook/34b762fc-5b9b-4abb-a05a-96c8fb9599f1"
|
||||
BACKEND_QRCODE_URL = "https://soul.quwanzhi.com/api/miniprogram/qrcode"
|
||||
BACKEND_QRCODE_URL = "https://soulapi.quwanzhi.com/api/miniprogram/qrcode"
|
||||
MINIPROGRAM_READ_BASE = "https://soul.quwanzhi.com/read"
|
||||
|
||||
# 海报尺寸(与小程序内一致,便于统一风格)
|
||||
POSTER_W = 300
|
||||
POSTER_H = 450
|
||||
# 海报尺寸(2x 放大,提升二维码识别率)
|
||||
POSTER_W = 600
|
||||
POSTER_H = 900
|
||||
# 高级感配色:深蓝渐变 + 青金点缀
|
||||
COLOR_BG_TOP = (26, 26, 46) # #1a1a2e
|
||||
COLOR_BG_BOTTOM = (22, 33, 62) # #16213e
|
||||
@@ -167,11 +167,10 @@ def _excerpt_to_feishu_text(excerpt: str) -> str:
|
||||
|
||||
|
||||
def build_poster(title: str, excerpt: str, qrcode_bytes: bytes) -> bytes:
|
||||
"""绘制海报图(PNG bytes)。标题=章节标题,样式与小程序内一致并略提升质感。"""
|
||||
"""绘制海报图(PNG bytes)。600x900 大图确保二维码可扫。"""
|
||||
img = Image.new("RGB", (POSTER_W, POSTER_H), COLOR_BG_TOP)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# 背景渐变(从上到下)
|
||||
for y in range(POSTER_H):
|
||||
t = y / POSTER_H
|
||||
r = int(COLOR_BG_TOP[0] * (1 - t) + COLOR_BG_BOTTOM[0] * t)
|
||||
@@ -179,37 +178,31 @@ def build_poster(title: str, excerpt: str, qrcode_bytes: bytes) -> bytes:
|
||||
b = int(COLOR_BG_TOP[2] * (1 - t) + COLOR_BG_BOTTOM[2] * t)
|
||||
draw.line([(0, y), (POSTER_W, y)], fill=(r, g, b))
|
||||
|
||||
# 顶部装饰条(加高一点更醒目)
|
||||
draw.rectangle([0, 0, POSTER_W, 5], fill=COLOR_ACCENT)
|
||||
draw.rectangle([0, 0, POSTER_W, 8], fill=COLOR_ACCENT)
|
||||
|
||||
# 小品牌标识(可选,弱化)
|
||||
font_small = _font(11)
|
||||
draw.text((20, 22), "Soul创业派对", fill=(150, 160, 180), font=font_small)
|
||||
font_small = _font(20)
|
||||
draw.text((40, 40), "Soul创业派对", fill=(150, 160, 180), font=font_small)
|
||||
|
||||
# 主标题:章节标题(字体加粗、略大,更易读)
|
||||
font_title = _font(19, bold=True)
|
||||
title_lines = _wrap_text(draw, title, font_title, POSTER_W - 40)
|
||||
y = 50
|
||||
for line in title_lines[:2]:
|
||||
draw.text((20, y), line, fill=COLOR_TITLE, font=font_title)
|
||||
y += 26
|
||||
font_title = _font(36, bold=True)
|
||||
title_lines = _wrap_text(draw, title, font_title, POSTER_W - 80)
|
||||
y = 90
|
||||
for line in title_lines[:3]:
|
||||
draw.text((40, y), line, fill=COLOR_TITLE, font=font_title)
|
||||
y += 48
|
||||
|
||||
# 分隔线
|
||||
y += 8
|
||||
draw.line([(20, y), (POSTER_W - 20, y)], fill=(100, 110, 130), width=1)
|
||||
y += 12
|
||||
draw.line([(40, y), (POSTER_W - 40, y)], fill=(100, 110, 130), width=1)
|
||||
|
||||
# 摘要(严格限制在摘要框内;每句空一行,避免挤/溢出)
|
||||
y += 28
|
||||
font_summary = _font(13)
|
||||
y += 36
|
||||
font_summary = _font(24)
|
||||
excerpt = (excerpt or "扫码阅读全文").strip()
|
||||
# 摘要框(增加边界感,但不抢视觉)
|
||||
bottom_h = 100
|
||||
box_x1, box_y1 = 16, y - 6
|
||||
box_x2, box_y2 = POSTER_W - 16, POSTER_H - bottom_h - 14
|
||||
bottom_h = 200
|
||||
box_x1, box_y1 = 32, y - 10
|
||||
box_x2, box_y2 = POSTER_W - 32, POSTER_H - bottom_h - 20
|
||||
try:
|
||||
draw.rounded_rectangle(
|
||||
[box_x1, box_y1, box_x2, box_y2],
|
||||
radius=10,
|
||||
radius=16,
|
||||
fill=(18, 26, 46),
|
||||
outline=(40, 55, 80),
|
||||
width=1,
|
||||
@@ -222,10 +215,10 @@ def build_poster(title: str, excerpt: str, qrcode_bytes: bytes) -> bytes:
|
||||
width=1,
|
||||
)
|
||||
|
||||
text_x = 20
|
||||
text_y = y
|
||||
max_w = POSTER_W - 40
|
||||
line_h = 18 # 12px 字体更舒服的行高
|
||||
text_x = 44
|
||||
text_y = y + 4
|
||||
max_w = POSTER_W - 88
|
||||
line_h = 34
|
||||
max_lines = max(1, int((box_y2 - text_y) / line_h))
|
||||
summary_lines = _excerpt_to_poster_lines(draw, excerpt, font_summary, max_w, max_lines)
|
||||
for line in summary_lines:
|
||||
@@ -233,26 +226,23 @@ def build_poster(title: str, excerpt: str, qrcode_bytes: bytes) -> bytes:
|
||||
draw.text((text_x, text_y), line, fill=COLOR_SUMMARY, font=font_summary)
|
||||
text_y += line_h
|
||||
|
||||
# 底部区域背景(深色块)
|
||||
draw.rectangle([0, POSTER_H - bottom_h, POSTER_W, POSTER_H], fill=COLOR_BOTTOM_BG)
|
||||
|
||||
# 底部文字
|
||||
font_hint = _font(13)
|
||||
draw.text((20, POSTER_H - 62), "长按识别小程序码", fill=COLOR_TITLE, font=font_hint)
|
||||
font_hint2 = _font(11)
|
||||
draw.text((20, POSTER_H - 40), "长按小程序码阅读全文", fill=COLOR_HINT, font=font_hint2)
|
||||
font_hint = _font(24)
|
||||
draw.text((40, POSTER_H - 130), "长按识别小程序码", fill=COLOR_TITLE, font=font_hint)
|
||||
font_hint2 = _font(20)
|
||||
draw.text((40, POSTER_H - 90), "长按小程序码阅读全文", fill=COLOR_HINT, font=font_hint2)
|
||||
|
||||
# 二维码(右下角,略留白;不放置手指图标)
|
||||
qr_size = 72
|
||||
qr_x = POSTER_W - 20 - qr_size
|
||||
qr_y = POSTER_H - 20 - qr_size
|
||||
qr_size = 160
|
||||
qr_x = POSTER_W - 40 - qr_size
|
||||
qr_y = POSTER_H - 30 - qr_size
|
||||
try:
|
||||
qr_img = Image.open(io.BytesIO(qrcode_bytes)).convert("RGB")
|
||||
qr_img = qr_img.resize((qr_size, qr_size), Image.Resampling.LANCZOS)
|
||||
img.paste(qr_img, (qr_x, qr_y))
|
||||
except Exception:
|
||||
draw.rectangle([qr_x, qr_y, qr_x + qr_size, qr_y + qr_size], outline=COLOR_ACCENT, width=2)
|
||||
draw.text((qr_x + 18, qr_y + 26), "扫码", fill=COLOR_ACCENT, font=_font(12))
|
||||
draw.text((qr_x + 40, qr_y + 60), "扫码", fill=COLOR_ACCENT, font=_font(24))
|
||||
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format="PNG")
|
||||
@@ -284,7 +274,7 @@ def fetch_qrcode_image(section_id: str) -> bytes | None:
|
||||
scene = f"id={section_id}"
|
||||
payload = {"scene": scene, "page": "pages/read/read", "width": 280}
|
||||
try:
|
||||
r = requests.post(BACKEND_QRCODE_URL, json=payload, timeout=15)
|
||||
r = requests.post(BACKEND_QRCODE_URL, json=payload, timeout=15, verify=False)
|
||||
body = r.json() if r.headers.get("content-type", "").startswith("application/json") else None
|
||||
if body and body.get("success") and body.get("image"):
|
||||
raw = body["image"]
|
||||
@@ -371,8 +361,14 @@ def main():
|
||||
|
||||
qrcode_bytes = fetch_qrcode_image(section_id)
|
||||
if not qrcode_bytes:
|
||||
print("无法获取小程序码,请确认后端 soul.quwanzhi.com 可访问且已配置小程序码接口")
|
||||
sys.exit(1)
|
||||
print("⚠️ 小程序码获取失败,使用占位图继续生成海报")
|
||||
# 生成一个简单的占位 PNG(白底+提示文字)
|
||||
_ph = Image.new("RGB", (280, 280), (240, 240, 240))
|
||||
_d = ImageDraw.Draw(_ph)
|
||||
_d.text((60, 120), "扫码阅读全文", fill=(100, 100, 100), font=_font(18))
|
||||
_buf = io.BytesIO()
|
||||
_ph.save(_buf, format="PNG")
|
||||
qrcode_bytes = _buf.getvalue()
|
||||
|
||||
poster_bytes = build_poster(title, excerpt, qrcode_bytes)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user