feat: news categorized by topic (5 categories, 5 each), with subtitles
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
"""Use DeepSeek to summarize top news into 500-word Chinese briefs."""
|
"""Use DeepSeek to summarize top news into categorized Chinese briefs (5 per category)."""
|
||||||
import json, os, requests
|
import json, os, requests
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
||||||
@ -20,38 +20,50 @@ def load_raw_news():
|
|||||||
|
|
||||||
|
|
||||||
def summarize(items):
|
def summarize(items):
|
||||||
"""Send raw news to DeepSeek and get summarized articles."""
|
|
||||||
# Build a condensed input for the AI (titles + summaries)
|
|
||||||
news_text = ""
|
news_text = ""
|
||||||
for i, item in enumerate(items[:20], 1):
|
for i, item in enumerate(items[:30], 1):
|
||||||
title = item.get("title", "")
|
title = item.get("title", "")
|
||||||
summary = item.get("summary", "")[:150].replace("<", "").replace(">", "")
|
summary = item.get("summary", "")[:150].replace("<", "").replace(">", "")
|
||||||
news_text += f"{i}. [{item['source']}] {title}\n {summary}\n\n"
|
source = item.get("source", "")
|
||||||
|
news_text += f"{i}. [{source}] {title}\n {summary}\n\n"
|
||||||
|
|
||||||
prompt = f"""你是一个新闻整理助手。以下是来自BBC世界新闻、BBC中文、Hacker News的最新资讯。
|
prompt = f"""你是一个新闻整理助手。以下是来自BBC世界新闻、BBC中文、新浪新闻、涌报、Hacker News的最新资讯。
|
||||||
|
|
||||||
请从以上内容中精选出最重要的10条新闻,每条用中文写成一段300-500字的精炼摘要。
|
请从以上内容中精选出最重要的新闻,按以下分类组织(每个分类最多5条):
|
||||||
要求:
|
|
||||||
1. 选择真正重要、有信息量的新闻(优先世界大事、科技突破、财经动向)
|
|
||||||
2. 每条摘要独立、完整,包含核心事实和背景
|
|
||||||
3. 语言简洁有力,适合快速阅读
|
|
||||||
4. 按重要性排序
|
|
||||||
5. 每条附上来源标签
|
|
||||||
|
|
||||||
输出格式为JSON数组:
|
分类要求:
|
||||||
[
|
- 国际要闻:全球政治、外交、军事
|
||||||
{{
|
- 科技前沿:AI、软件、硬件、互联网
|
||||||
"rank": 1,
|
- 财经动向:市场、经济、商业
|
||||||
"title": "精炼标题(20字以内)",
|
- 中国热点:中国相关新闻
|
||||||
"source": "BBC World",
|
- 社会生活:健康、环境、文化、民生
|
||||||
"summary": "300-500字中文摘要..."
|
|
||||||
}},
|
|
||||||
...
|
|
||||||
]
|
|
||||||
|
|
||||||
只输出JSON,不要其他内容。
|
每条新闻格式:
|
||||||
|
## 小标题(10字以内概括核心)
|
||||||
|
|
||||||
今日要闻原始数据:
|
正文(200-300字中文精炼摘要,包含核心事实和背景)
|
||||||
|
|
||||||
|
输出格式为JSON:
|
||||||
|
{{
|
||||||
|
"categories": [
|
||||||
|
{{
|
||||||
|
"name": "国际要闻",
|
||||||
|
"items": [
|
||||||
|
{{"rank": 1, "subtitle": "小标题", "title": "原标题", "source": "BBC World", "summary": "正文..."}},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
|
||||||
|
注意:
|
||||||
|
- 每个分类最多5条
|
||||||
|
- 小标题要精炼抓人
|
||||||
|
- 摘要要有信息量,不要空话
|
||||||
|
- 只输出JSON,不要其他内容
|
||||||
|
|
||||||
|
原始新闻:
|
||||||
{news_text}"""
|
{news_text}"""
|
||||||
|
|
||||||
resp = requests.post(
|
resp = requests.post(
|
||||||
@ -60,35 +72,39 @@ def summarize(items):
|
|||||||
json={
|
json={
|
||||||
"model": MODEL,
|
"model": MODEL,
|
||||||
"messages": [{"role": "user", "content": prompt}],
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
"temperature": 0.5,
|
"temperature": 0.4,
|
||||||
"max_tokens": 6000,
|
"max_tokens": 8000,
|
||||||
},
|
},
|
||||||
timeout=120,
|
timeout=180,
|
||||||
)
|
)
|
||||||
|
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
print(f"API error: {resp.status_code} {resp.text[:200]}")
|
print(f"API error: {resp.status_code} {resp.text[:200]}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
result = resp.json()
|
content = resp.json()["choices"][0]["message"]["content"]
|
||||||
content = result["choices"][0]["message"]["content"]
|
|
||||||
|
|
||||||
# Parse JSON from response
|
|
||||||
content = content.strip()
|
content = content.strip()
|
||||||
if content.startswith("```"):
|
if content.startswith("```"):
|
||||||
content = content.split("\n", 1)[1]
|
lines = content.split("\n")
|
||||||
content = content.rsplit("\n", 1)[0]
|
content = "\n".join(lines[1:-1]) if lines[-1].strip() == "```" else "\n".join(lines[1:])
|
||||||
if content.endswith("```"):
|
|
||||||
content = content[:-3]
|
|
||||||
content = content.strip()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
articles = json.loads(content)
|
result = json.loads(content)
|
||||||
except:
|
except:
|
||||||
print(f"JSON parse failed, content: {content[:300]}")
|
# Try to fix common JSON issues
|
||||||
return None
|
content = content.strip()
|
||||||
|
# Remove trailing commas before closing brackets
|
||||||
|
import re
|
||||||
|
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)}")
|
||||||
|
print(f"First 800 chars: {content[:800]}")
|
||||||
|
return None
|
||||||
|
|
||||||
return articles
|
return result
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@ -98,21 +114,23 @@ if __name__ == "__main__":
|
|||||||
print("No news data")
|
print("No news data")
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
print(f"Loaded {len(items)} raw news items. Summarizing...")
|
print(f"Loaded {len(items)} raw news items. AI summarizing by category...")
|
||||||
articles = summarize(items)
|
data = summarize(items)
|
||||||
|
|
||||||
if not articles:
|
if not data:
|
||||||
print("Summarization failed")
|
print("Summarization failed")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
"updated_at": now,
|
"updated_at": now,
|
||||||
"total": len(articles),
|
"categories": data.get("categories", []),
|
||||||
"articles": articles,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
total = sum(len(c["items"]) for c in result["categories"])
|
||||||
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
|
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
|
||||||
with open(OUTPUT, "w", encoding="utf-8") as f:
|
with open(OUTPUT, "w", encoding="utf-8") as f:
|
||||||
json.dump(result, f, ensure_ascii=False, indent=2)
|
json.dump(result, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
print(f"Written {len(articles)} summarized articles to {OUTPUT}")
|
print(f"Written {total} articles across {len(result['categories'])} categories")
|
||||||
|
for c in result["categories"]:
|
||||||
|
print(f" {c['name']}: {len(c['items'])} items")
|
||||||
|
|||||||
Reference in New Issue
Block a user