jiachenlong/backend/app/utils/coolbot_matcher.py

263 lines
8.1 KiB
Python
Raw Normal View History

# coolbot_matcher - 一尘数据库号码匹配工具
# Version: 0.0.2 (2026-04-30)
# 描述:从一尘数据库(coolbot_data)查询匹配的藏品号码
# 更新:号码分类规则修正
from typing import List, Optional
from sqlalchemy import text
from sqlalchemy.orm import Session
from app.core.coolbot_db import coolbot_engine
def classify_number(number: str) -> str:
"""根据号码特征分类
规则2026-04-30修正版
首先区分标百标十单张
- 单张J后面9位
- 标十J后面8位最后一位是1
- 标百J后面7位最后两位是01
分类优先级
| 类型 | 排除 | 可用数字 | 必须包含 |
|------|------|----------|----------|
| 通货 | - | - | 4 |
| 带7号 | 4 | - | 7 |
| 永恒号 | 47 | - | - |
| 圆圆号 | 123457 | 0689 | - |
| 倒置号 | 23457 | 01689 | 1 |
| 金马王 | 12347 | 05689 | 5 |
| 金马号 | 2347 | 015689 | 1,5 |
| 金山王 | 12457 | 03689 | 3 |
| 天马王 | 1247 | 035689 | 3,5 |
| 金山号 | 2457 | 013689 | 1,3 |
| 天马号 | 247 | 0135689 | 1,3,5 |
| 朦胧王 | 13457 | - | - |
| 朦胧号 | 3457 | - | - |
| 如意号 | 1347 | - | - |
| 钻石号 | 347 | - | - |
"""
if not number:
return "未知"
if number.startswith('J0'):
digits = number[2:]
elif number.startswith('J'):
digits = number[1:]
else:
return "未知"
if len(digits) == 9:
d = digits
elif len(digits) == 8:
d = digits[:8]
elif len(digits) == 7:
d = digits
else:
return "未知"
unique = set(d)
# 1. 通货带4
if '4' in unique:
return "通货"
# 2. 带7号无4有7
if '7' in unique:
return "带7号"
# 3. 圆圆号无1234570689四个数字任意组合
if unique <= {'0', '6', '8', '9'}:
return "圆圆号"
# 4. 永恒号只有0和1无47但不符合圆圆号/倒置号)
if unique <= {'0', '1'}:
return "永恒号"
# 5. 倒置号01689组合必须有1且包含6/8/9中的至少一个
if unique <= {'0', '1', '6', '8', '9'} and '1' in unique and unique & {'6', '8', '9'}:
return "倒置号"
# 6. 金马王无1234705689组合必须有5排除1
if unique <= {'0', '5', '6', '8', '9'} and '5' in unique and '1' not in unique:
return "金马王"
# 7. 金马号无2347015689组合必须有1和5包含1
if unique <= {'0', '1', '5', '6', '8', '9'} and '1' in unique and '5' in unique:
return "金马号"
# 8. 金山王无1245703689组合必须有3排除1和5
if unique <= {'0', '3', '6', '8', '9'} and '3' in unique and '1' not in unique and '5' not in unique:
return "金山王"
# 9. 天马王无1247035689组合必须有3和5排除1
if unique <= {'0', '3', '5', '6', '8', '9'} and '3' in unique and '5' in unique and '1' not in unique:
return "天马王"
# 10. 金山号无2457013689组合必须有1和3排除5
if unique <= {'0', '1', '3', '6', '8', '9'} and '1' in unique and '3' in unique and '5' not in unique:
return "金山号"
# 11. 天马号无2470135689组合必须有1、3和5
if unique <= {'0', '1', '3', '5', '6', '8', '9'} and '1' in unique and '3' in unique and '5' in unique:
return "天马号"
# 12. 朦胧王无13457
if not unique & {'1', '3', '4', '5', '7'}:
return "朦胧王"
# 13. 朦胧号无3457
if not unique & {'3', '4', '5', '7'}:
return "朦胧号"
# 14. 如意号无1347
if not unique & {'1', '3', '4', '7'}:
return "如意号"
# 15. 钻石号无347
if not unique & {'3', '4', '7'}:
return "钻石号"
# 16. 永恒号兜底无47
if '7' not in unique:
return "永恒号"
return "其他"
def check_match(col_number: str, expect_number: str, expect_category: str) -> bool:
"""检查藏品号码是否符合期望的分类"""
if not col_number or not expect_category:
return False
col_cat = classify_number(col_number)
if col_cat == expect_category:
return True
if expect_category == "其他":
return check_number_pattern(col_number, expect_number)
return False
def check_number_pattern(col_number: str, expect_number: str) -> bool:
"""检查号码特征匹配"""
if not col_number or not expect_number:
return False
if col_number.startswith('J0'):
col_digits = col_number[2:]
else:
col_digits = col_number[1:] if len(col_number) > 1 else col_number
if expect_number.startswith('J0'):
exp_digits = expect_number[2:]
else:
exp_digits = expect_number[1:] if len(expect_number) > 1 else expect_number
min_len = min(len(col_digits), len(exp_digits))
return col_digits[:min_len] == exp_digits[:min_len]
def get_match_type(expect_number: str) -> str:
"""判断匹配类型"""
if not expect_number:
return "unknown"
if expect_number.startswith('J0'):
digits = expect_number[2:]
elif expect_number.startswith('J'):
digits = expect_number[1:]
else:
return "unknown"
if len(digits) == 8:
return "ten"
elif len(digits) == 7:
return "hundred"
elif len(digits) == 9:
return "single"
return "unknown"
def match_self_collections_count(db: Session, user_id: str, expect_number: str, expect_category: str) -> int:
"""计算匹配藏品数量(用户自有藏品)"""
from app.models.models import Collection
if not expect_number:
return 0
collections = db.query(Collection).filter(
Collection.f99_91_user_id == user_id,
Collection.f01_04_status == "in_collection"
).all()
count = 0
for c in collections:
number = c.f02_10_prefix_serial or ''
if check_match(number, expect_number, expect_category):
count += 1
return count
def match_collections_count_from_coolbot(expect_number: str, expect_category: str) -> int:
"""计算匹配藏品数量(一尘数据库)"""
if not expect_number:
return 0
query = text("""
SELECT id, crown_code FROM collections
WHERE crown_code IS NOT NULL
AND crown_code != ''
AND crown_code LIKE 'J0%'
""")
try:
with coolbot_engine.connect() as conn:
result = conn.execute(query)
return sum(1 for row in result if check_match(row[1], expect_number, expect_category))
except Exception as e:
print(f"Error: {e}")
return 0
def match_collections_list_from_coolbot(expect_number: str, expect_category: str, limit: int = 20) -> List[dict]:
"""获取匹配的藏品列表(一尘数据库)"""
if not expect_number:
return []
query = text("""
SELECT id, name, category, crown_code, price, post_title, post_url, author, post_crawled_at
FROM collections
WHERE crown_code IS NOT NULL
AND crown_code != ''
AND crown_code LIKE 'J0%'
""")
try:
with coolbot_engine.connect() as conn:
result = conn.execute(query)
matched = []
for row in result:
if check_match(row[3], expect_number, expect_category):
matched.append({
"id": row[0],
"name": row[1],
"category": row[2],
"crown_code": row[3],
"price": float(row[4]) if row[4] else None,
"post_title": row[5],
"post_url": row[6],
"author": row[7],
"post_crawled_at": row[8].isoformat() if row[8] else None
})
if len(matched) >= limit:
break
return matched
except Exception as e:
print(f"Error: {e}")
return []