feat: 新增作息报时器功能并替换短链接前缀为/to/

- 新增作息报时器独立模块,包含完整的日程管理、语音播报和待机功能
- 短链接正式前缀由/l/改为/to/,解决手机小屏下与I、i、1字形混淆问题
- 保留旧前缀/l/、/L/、/I/、/i/兼容已分发的旧短链
- 新增短码大小写兜底匹配,仅唯一匹配时生效避免歧义
- 新增防爆紧急替换功能,可轮换首页鉴权并替换短链接
- 新增多个调试和集成测试脚本,保障数据安全和功能回归
This commit is contained in:
yangxiangyuan
2026-10-09 14:04:37 +08:00
parent ac475b6659
commit a3e8911deb
131 changed files with 7695 additions and 60 deletions
+53
View File
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# 调试:trim_label 单格验证(r0c0 / r3c0 / r2c8)
import os
import sys
import cv2
import numpy as np
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'tools'))
import tool_crop_mall_logos as M # noqa: E402
HERE = os.path.dirname(os.path.abspath(__file__))
img = M.imread_u(M.DEFAULT_SRC)
warped = M.warp_board(img, M.detect_board_quad(img))
blocks = M.detect_confident_blocks(warped)
g = M.fit_grid(blocks)
print('row_top', [round(v) for v in g['row_top']])
print('col_center', [round(v) for v in g['col_center']])
for (ri, ci) in [(4, 1), (3, 8), (0, 0), (2, 8), (3, 6), (6, 10), (5, 0), (6, 0)]:
b = g['grid'].get((ri, ci))
if b is not None:
x0, y0, x1, y1 = b['x'] - 2, b['y'] - 2, b['x'] + b['w'] + 2, b['y'] + b['h'] + 2
kind = 'detect'
else:
cx = g['col_center'][ci]
x0, x1 = int(cx - g['pw'] / 2 - 2), int(cx + g['pw'] / 2 + 2)
y0, y1 = int(g['row_top'][ri] - 2), int(g['row_top'][ri] + g['ph'] + 2)
kind = 'fallback'
crop = warped[y0:y1, x0:x1]
gray = cv2.cvtColor(crop, cv2.COLOR_BGR2GRAY)
h = gray.shape[0]
print('--- r%dc%d %s bbox h=%d' % (ri, ci, kind, h))
for y in range(h - 1, max(0, h - 90), -6):
row = gray[y]
print(' y=%3d dark=%.3f mean=%.0f' % (y, float(np.mean(row < 160)), float(np.mean(row))))
t = M.trim_label(crop)
print(' trim: %d -> %d' % (crop.shape[0], t.shape[0]))
if (ri, ci) in [(6, 10), (6, 0)]:
import numpy as _np
gg = cv2.cvtColor(crop, cv2.COLOR_BGR2GRAY).astype(_np.float32)
dk = (gg < 160).mean(axis=1)
mn = gg.mean(axis=1)
ww = gg.shape[1]
a0, a1 = int(ww * 0.2), int(ww * 0.8)
dc = (gg[:, a0:a1] < 160).mean(axis=1)
do = ((gg[:, :a0] < 160).sum(axis=1) + (gg[:, a1:] < 160).sum(axis=1)) / float(ww - (a1 - a0))
rt = (dc + 0.004) / (do + 0.004)
it = (dk >= 0.04) & (mn <= 220) & (rt > 2.5)
ig = (dk < 0.12) & (mn >= 165) & (~it)
for y in range(crop.shape[0] - 1, int(crop.shape[0] * 0.4), -4):
print(' y=%3d dark=%.3f mean=%3.0f ratio=%5.2f text=%d gap=%d' % (y, dk[y], mn[y], rt[y], it[y], ig[y]))
M.imwrite_u(os.path.join(HERE, 'trim_r%dc%d.jpg' % (ri, ci)), t)