Files
inspiration-collector/scripts/summarize_research.py

168 lines
5.4 KiB
Python
Raw Permalink 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.

"""Use DeepSeek to summarize AI/quant research RSS into categorized briefs.
v2: back-fills pub_time from raw RSS data after AI summarization.
"""
import json, os, requests, re
from datetime import datetime, timezone, timedelta
from dateutil import parser as dtparser
API_KEY = "sk-bbca4a0380d549389f0d27cdea0b5228"
API_URL = "https://api.deepseek.com/v1/chat/completions"
MODEL = "deepseek-v4-flash"
INPUT = "/var/www/nav/data/research.json"
OUTPUT = "/var/www/nav/data/research_summary.json"
tz = timezone(timedelta(hours=8))
def load_raw():
if not os.path.exists(INPUT):
return []
with open(INPUT) as f:
data = json.load(f)
return data.get("items", [])
def build_time_lookup(raw_items):
"""Build lookup: title -> pub_time (Beijing time string)."""
lookup = {}
for item in raw_items:
title = item.get("title", "").strip()
published = item.get("published", "").strip()
if not title or not published:
continue
try:
dt = dtparser.parse(published)
if dt.tzinfo:
dt = dt.astimezone(tz)
else:
dt = dt.replace(tzinfo=tz)
now = datetime.now(tz)
if dt.date() == now.date():
time_str = dt.strftime("%H:%M")
else:
time_str = dt.strftime("%m-%d %H:%M")
lookup[title] = time_str
except Exception:
continue
return lookup
def match_pub_time(items, lookup):
for item in items:
if "pub_time" in item:
continue
title = item.get("title", "").strip()
if title in lookup:
item["pub_time"] = lookup[title]
else:
for raw_title, time_val in lookup.items():
short = min(len(raw_title), len(title))
if short > 10 and (raw_title[:short] in title or title[:short] in raw_title):
item["pub_time"] = time_val
break
def summarize(items):
news_text = ""
for i, item in enumerate(items[:100], 1):
title = item.get("title", "")
summary = item.get("summary", "")[:300].replace("<", "").replace(">", "")
source = item.get("source", "")
link = item.get("link", "")
news_text += f"{i}. [{source}] {title}\n {summary}\n url: {link}\n\n"
prompt = f"""你是一个 AI/量化研究资讯编辑。请从原始 RSS 中精选出**最有价值的论文和博客文章**,按主题分类。
## 选稿标准
- ArXiv 论文AI 重大突破LLM、Agent、多模态、量化交易新方法
- 博客文章:有实操价值的策略思路、代码实现、回测分析
- 过滤:纯新闻通告、产品广告、重复性内容
## 分类(每个分类 8-15 条)
- AI 前沿论文ArXiv cs.AI / cs.LG 重要论文)
- 量化交易研究(策略思路、回测方法、风险管理)
- 行业动态AI 公司、产品发布、监管动态)
## 输出格式
每条rank, subtitle15-30字, title必须与原始标题完全一致这是时间匹配的关键, source, link, summary200-400字说清楚这篇讲了什么、有什么用
## 原始内容
{news_text}
JSON格式: {{"categories": [{{"name":"分类名","items":[{{"rank":1,"subtitle":"...","title":"...","source":"...","link":"...","summary":"..."}}]}}]}}"""
resp = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={
"model": MODEL,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.3,
"max_tokens": 16000,
},
timeout=180,
)
if resp.status_code != 200:
print(f"API error: {resp.status_code}")
return None
content = resp.json()["choices"][0]["message"]["content"].strip()
if content.startswith("```"):
lines = content.split("\n")
content = "\n".join(lines[1:-1]) if lines[-1].strip() == "```" else "\n".join(lines[1:])
try:
result = json.loads(content)
except:
content = re.sub(r',\s*}', '}', content)
content = re.sub(r',\s*]', ']', content)
try:
result = json.loads(content)
except:
print(f"JSON parse failed, len={len(content)}")
return None
return result
def run():
now = datetime.now(tz).strftime("%Y-%m-%d %H:%M")
raw_items = load_raw()
if not raw_items:
print("No research data")
exit(0)
print(f"Loaded {len(raw_items)} research items. AI summarizing...")
data = summarize(raw_items)
if not data:
print("Summarization failed")
exit(1)
# Back-fill pub_time
time_lookup = build_time_lookup(raw_items)
matched = 0
for cat in data.get("categories", []):
match_pub_time(cat["items"], time_lookup)
matched += sum(1 for item in cat["items"] if "pub_time" in item)
print(f"Matched pub_time for {matched} articles")
result = {
"updated_at": now,
"categories": data.get("categories", []),
}
total = sum(len(c["items"]) for c in result["categories"])
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
with open(OUTPUT, "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
print(f"Written {total} research briefs -> {OUTPUT}")
for c in result["categories"]:
print(f" {c['name']}: {len(c['items'])} items")
if __name__ == "__main__":
run()