jiachenlong/backend/app/utils/coolbot_matcher.py

263 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 []