添加批量行情解析API和分页功能修复
This commit is contained in:
parent
446cd32484
commit
9e237c88a4
|
|
@ -0,0 +1,2 @@
|
|||
from app.models.deal_info import DealInfo
|
||||
from app.models.models import User, Collection
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
# 资讯API路由
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Body
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
|
@ -1082,3 +1082,179 @@ def get_seek_list_all(
|
|||
content=result,
|
||||
headers={"X-Total-Pages": str(total_pages), "X-Total-Count": str(total_count)}
|
||||
)
|
||||
def parse_deals_locally(text: str, default_packaging: str = '', default_date: str = '', default_platform: str = ''):
|
||||
"""本地正则解析批量行情文本"""
|
||||
import re
|
||||
from datetime import datetime
|
||||
results = []
|
||||
|
||||
# 尝试从文本中提取日期(可能出现在标题或时间戳中)
|
||||
# 格式如: 3月29日, 2026年3月29日, 2026-03-29
|
||||
date_patterns = [
|
||||
r'(\d{1,2})月(\d{1,2})日',
|
||||
r'(\d{4})年(\d{1,2})月(\d{1,2})日',
|
||||
r'(\d{4})-(\d{1,2})-(\d{1,2})'
|
||||
]
|
||||
|
||||
extracted_date = None
|
||||
for pattern in date_patterns:
|
||||
match = re.search(pattern, text)
|
||||
if match:
|
||||
try:
|
||||
if len(match.groups()) == 2:
|
||||
# 3月29日 - 使用当前年份
|
||||
extracted_date = f"2026-{int(match.group(1)):02d}-{int(match.group(2)):02d}"
|
||||
elif len(match.groups()) == 3:
|
||||
if int(match.group(1)) > 2000:
|
||||
# 2026年3月29日
|
||||
extracted_date = f"{match.group(1)}-{int(match.group(2)):02d}-{int(match.group(3)):02d}"
|
||||
else:
|
||||
# 3月29日格式
|
||||
extracted_date = f"2026-{int(match.group(1)):02d}-{int(match.group(2)):02d}"
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
# 默认使用今天
|
||||
default_date = datetime.now().strftime('%Y-%m-%d')
|
||||
deal_date = extracted_date or default_date
|
||||
|
||||
lines = text.strip().split('\n')
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line or 'J0' not in line:
|
||||
continue
|
||||
|
||||
# 提取冠字号 J0 + 8-9位数字
|
||||
serial_match = re.search(r'J0(\d{8,9})', line)
|
||||
if not serial_match:
|
||||
continue
|
||||
|
||||
serial_num = serial_match.group(1)
|
||||
if len(serial_num) == 9:
|
||||
serial_num = serial_num[:8]
|
||||
serial = 'J0' + serial_num
|
||||
|
||||
# 提取价格 ¥xxx,xxx 或 xxx,xxx(必须在J0之后)
|
||||
serial_pos = line.find(serial)
|
||||
after_serial = line[serial_pos + len(serial):]
|
||||
price_match = re.search(r'[¥¥]?\s*([1-9][\d,]{2,})', after_serial)
|
||||
if not price_match:
|
||||
continue
|
||||
price = int(price_match.group(1).replace(',', ''))
|
||||
|
||||
# 提取卖家(价格后面的中文字符)
|
||||
after_price_pos = after_serial.find(price_match.group(0)) + len(price_match.group(0))
|
||||
after_price = after_serial[after_price_pos:]
|
||||
seller_match = re.search(r'([^\d\s¥¥]+?)(?:\s*$|\s*\n)', after_price)
|
||||
seller = seller_match.group(1).strip() if seller_match else ''
|
||||
|
||||
# 分类判断
|
||||
digits = serial_num
|
||||
d = digits
|
||||
category = '通货'
|
||||
if not any(c in d for c in ['1','2','3','4','5','7']): category = '圆圆号'
|
||||
elif not any(c in d for c in ['2','3','4','5','7']): category = '倒置号'
|
||||
elif not any(c in d for c in ['1','2','3','4','7']): category = '金马王'
|
||||
elif not any(c in d for c in ['2','3','4','7']): category = '金马号'
|
||||
elif not any(c in d for c in ['1','2','4','5','7']): category = '金山王'
|
||||
elif not any(c in d for c in ['1','2','4','7']): category = '天马王'
|
||||
elif not any(c in d for c in ['2','4','5','7']): category = '金山号'
|
||||
elif not any(c in d for c in ['2','4','7']): category = '天马号'
|
||||
elif not any(c in d for c in ['1','3','4','5','7']): category = '朦胧王'
|
||||
elif not any(c in d for c in ['3','4','5','7']): category = '朦胧号'
|
||||
elif not any(c in d for c in ['1','3','4','7']): category = '如意号'
|
||||
elif not any(c in d for c in ['3','4','7']): category = '钻石号'
|
||||
elif not any(c in d for c in ['4','7']): category = '永恒号'
|
||||
elif '4' not in d: category = '带7号'
|
||||
|
||||
# 提取评级机构 PCGS/PMG/ACG/爱藏
|
||||
grade = ''
|
||||
grading_company = ''
|
||||
packaging = '单张'
|
||||
|
||||
if 'PC69' in line or 'PC68' in line or 'PC67' in line:
|
||||
grade_match = re.search(r'PC(6[789]|5\d?)', line)
|
||||
grade = 'PC' + grade_match.group(1) if grade_match else ''
|
||||
grading_company = 'PCGS'
|
||||
elif 'PMG68' in line or 'PMG67' in line:
|
||||
grade_match = re.search(r'PMG(6[789]|5\d?)', line)
|
||||
grade = 'PMG' + grade_match.group(1) if grade_match else ''
|
||||
grading_company = 'PMG'
|
||||
elif 'ACG' in line:
|
||||
grade_match = re.search(r'ACG(6[789]|5\d?)', line)
|
||||
grade = 'ACG' + grade_match.group(1) if grade_match else ''
|
||||
grading_company = 'ACG'
|
||||
elif '爱藏67+' in line:
|
||||
grade = '67+'
|
||||
grading_company = '爱藏'
|
||||
elif '爱藏67' in line:
|
||||
grade = '67'
|
||||
grading_company = '爱藏'
|
||||
|
||||
# 判断包装类型
|
||||
packaging = '单张'
|
||||
|
||||
# 如果传入了默认包装类型,先使用默认
|
||||
if default_packaging:
|
||||
packaging = default_packaging
|
||||
|
||||
# 简化识别:带"刀"字=标百,带"标"字=标十
|
||||
if '刀' in line:
|
||||
packaging = '标百'
|
||||
elif '标' in line:
|
||||
packaging = '标十'
|
||||
|
||||
# 尾号判断:如果冠字号尾号是01/11/21/31/41/51/61/71/81/91,且有刀/标字样,基本确认是标百
|
||||
if len(serial_num) >= 2:
|
||||
tail = serial_num[-2:]
|
||||
if tail in ['01', '11', '21', '31', '41', '51', '61', '71', '81', '91']:
|
||||
if '刀' in line or ('标' in line and packaging == '单张'):
|
||||
packaging = '标百'
|
||||
packaging = '标百'
|
||||
|
||||
# 如果没有刀/标字样,但尾号是01且没有其他特征,可能是标百
|
||||
if packaging == '单张' and len(serial_num) >= 2:
|
||||
tail = serial_num[-2:]
|
||||
if tail == '01':
|
||||
# 检查是否在特定语境下
|
||||
packaging = '标百'
|
||||
|
||||
# 计算尾号和大小号
|
||||
tail_number = ''
|
||||
size_type = ''
|
||||
if packaging == '标十' and len(serial_num) >= 2:
|
||||
tail_number = serial_num[-2:]
|
||||
size_type = tail_number in ['01','11','21','31','41','51'] and '小号' or '大号'
|
||||
elif packaging == '标百' and len(serial_num) >= 3:
|
||||
tail_number = serial_num[-3:]
|
||||
size_type = tail_number in ['101','201','301','401','501'] and '小号' or '大号'
|
||||
|
||||
results.append({
|
||||
'serial': serial,
|
||||
'price': price,
|
||||
'category': category,
|
||||
'seller': seller,
|
||||
'packaging': packaging,
|
||||
'grade': grade,
|
||||
'grading_company': grading_company,
|
||||
'deal_date': deal_date or default_date, # 成交时间
|
||||
'entry_date': default_date, # 录入时间
|
||||
'is_graded': bool(grade),
|
||||
'tail_number': tail_number, # 尾号
|
||||
'size_type': size_type, # 大小号
|
||||
'platform': default_platform # 平台
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
@router.post("/batch-parse-local")
|
||||
async def batch_parse_deals_local(request: dict = Body(...)):
|
||||
"""本地正则解析批量行情文本(无需AI)"""
|
||||
text = request.get('text', '')
|
||||
default_packaging = request.get('defaultPackaging', '')
|
||||
default_date = request.get('defaultDate', '')
|
||||
default_platform = request.get('defaultPlatform', '')
|
||||
results = parse_deals_locally(text, default_packaging, default_date, default_platform)
|
||||
return {"success": True, "data": results}
|
||||
|
|
|
|||
Loading…
Reference in New Issue