108 lines
4.3 KiB
Python
108 lines
4.3 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""LLM-based price extraction for post titles"""
|
|||
|
|
import os, json, re
|
|||
|
|
import httpx
|
|||
|
|
|
|||
|
|
LLM_API_KEY = os.environ.get('LLM_API_KEY', 'sk-sp-d5ce68bb203e48ca857c2aea25255b26')
|
|||
|
|
LLM_API_URL = os.environ.get('LLM_API_URL', 'https://coding.dashscope.aliyuncs.com/v1/chat/completions')
|
|||
|
|
LLM_MODEL = os.environ.get('LLM_MODEL', 'qwen3.5-plus')
|
|||
|
|
|
|||
|
|
def extract_price_with_llm(title: str) -> dict:
|
|||
|
|
"""Use LLM to extract price from title. Returns dict with price, unit, confidence."""
|
|||
|
|
prompt = f"""你是一个钱币收藏市场的价格分析师。请从以下帖子标题中提取信息:
|
|||
|
|
|
|||
|
|
标题:"{title}"
|
|||
|
|
|
|||
|
|
请仔细分析:
|
|||
|
|
1. 这个帖子是求购还是出售?(收/求/购 = 求购,出/售 = 出售)
|
|||
|
|
2. 实际交易价格是多少?(数字+单位)
|
|||
|
|
3. 价格单位是什么?(元/张、元/刀、元/条、元/套 等)
|
|||
|
|
|
|||
|
|
注意:
|
|||
|
|
- "求2组"不是价格,"2组"只是数量
|
|||
|
|
- "3月"不是价格,是日期
|
|||
|
|
- 只有明确表示交易价格的才是价格
|
|||
|
|
|
|||
|
|
请用JSON格式回答:{{"post_type":"want/deal/null","price":数字或null,"unit":"元/张等","reason":"解释"}}
|
|||
|
|
只回答JSON,不要其他内容。"""
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
with httpx.Client(timeout=30.0) as client:
|
|||
|
|
response = client.post(
|
|||
|
|
LLM_API_URL,
|
|||
|
|
headers={
|
|||
|
|
"Authorization": f"Bearer {LLM_API_KEY}",
|
|||
|
|
"Content-Type": "application/json"
|
|||
|
|
},
|
|||
|
|
json={
|
|||
|
|
"model": LLM_MODEL,
|
|||
|
|
"messages": [{"role": "user", "content": prompt}],
|
|||
|
|
"temperature": 0.1
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
if response.status_code == 200:
|
|||
|
|
result = response.json()
|
|||
|
|
content = result['choices'][0]['message']['content'].strip()
|
|||
|
|
# Extract JSON
|
|||
|
|
if '{' in content:
|
|||
|
|
json_str = content[content.find('{'):content.rfind('}')+1]
|
|||
|
|
return json.loads(json_str)
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"LLM error: {e}")
|
|||
|
|
return {"post_type": None, "price": None, "unit": None, "reason": "LLM failed"}
|
|||
|
|
|
|||
|
|
def batch_extract_prices(titles: list) -> list:
|
|||
|
|
"""Batch extract prices from multiple titles"""
|
|||
|
|
prompt = f"""你是一个钱币收藏市场的价格分析师。请批量分析以下帖子标题,提取求购/出售价格信息。
|
|||
|
|
|
|||
|
|
标题列表:
|
|||
|
|
{chr(10).join([f"{i+1}. {t}" for i, t in enumerate(titles)])}
|
|||
|
|
|
|||
|
|
对于每个标题,判断:
|
|||
|
|
- post_type: "want"表示求购,"deal"表示出售,"null"表示无法判断
|
|||
|
|
- price: 实际交易价格数字(元),如果不是价格或无法判断则填null
|
|||
|
|
- unit: 价格单位,如"元/张"、"元/刀"、"元/条"、"元/套"、"元"等
|
|||
|
|
|
|||
|
|
只返回JSON数组格式:[{{"idx":1,"post_type":"want","price":120,"unit":"元/张","reason":"..."}},...]
|
|||
|
|
只回答JSON数组。"""
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
with httpx.Client(timeout=60.0) as client:
|
|||
|
|
response = client.post(
|
|||
|
|
LLM_API_URL,
|
|||
|
|
headers={
|
|||
|
|
"Authorization": f"Bearer {LLM_API_KEY}",
|
|||
|
|
"Content-Type": "application/json"
|
|||
|
|
},
|
|||
|
|
json={
|
|||
|
|
"model": LLM_MODEL,
|
|||
|
|
"messages": [{"role": "user", "content": prompt}],
|
|||
|
|
"temperature": 0.1
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
if response.status_code == 200:
|
|||
|
|
result = response.json()
|
|||
|
|
content = result['choices'][0]['message']['content'].strip()
|
|||
|
|
if '[' in content:
|
|||
|
|
json_str = content[content.find('['):content.rfind(']')+1]
|
|||
|
|
return json.loads(json_str)
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"Batch LLM error: {e}")
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
if __name__ == '__main__':
|
|||
|
|
test_titles = [
|
|||
|
|
"求2组小龙鈔无四七标十,爱藏67+三星",
|
|||
|
|
"765出一组无三四七标十马钞三包到手 可小义",
|
|||
|
|
"2000元出一组龙钞朦胧号5张PMG68分",
|
|||
|
|
"收购龙钞带4标十 1200元/张",
|
|||
|
|
"低价出蛇钞一刀 已经刀切好",
|
|||
|
|
"求购小龙钞无47标十 450元每张",
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
print("Testing LLM price extraction:")
|
|||
|
|
for title in test_titles:
|
|||
|
|
result = extract_price_with_llm(title)
|
|||
|
|
print(f"\n标题: {title}")
|
|||
|
|
print(f"结果: {result}")
|