Phase1: 效果数据真实化

- 替换scheduler.py中假随机数metrics_sync为知乎API自动获取
- 新增 POST /api/metrics/zhihu-fetch 知乎公开数据API端点
- metrics.html新增「数据录入」tab:手动录入表单+已有数据列表+知乎自动获取
- gitignore清理已跟踪的生成文件(outlines/research/images/cache)
This commit is contained in:
Yuzhiran Dev
2026-05-20 19:04:35 +08:00
parent eb800c5acc
commit 09da2f9dc4
176 changed files with 331 additions and 4756 deletions
+39 -46
View File
@@ -165,12 +165,12 @@ class TaskScheduler:
logger.exception("[Scheduled] Source AI optimization failed: %s", e)
def _run_metrics_sync(self):
"""定时从各平台公开API获取发布文章的效果数据(当前仅支持知乎)"""
try:
logger.info("[Scheduled] Starting metrics sync...")
logger.info("[Scheduled] Starting metrics sync (zhihu auto-fetch)...")
from ..database import SessionLocal
from ..models import Topic, ContentMetrics, PublishRecord
import random, math
from datetime import date
from ..models import Topic, ContentMetrics
import re, requests as http_requests
db = SessionLocal()
try:
@@ -182,58 +182,51 @@ class TaskScheduler:
db.close()
return
random.seed(42)
multipliers = {
"zhihu": {"v": 1.0, "l": 1.2, "f": 0.6, "c": 1.5, "s": 0.3},
"wechat": {"v": 1.8, "l": 0.6, "f": 0.4, "c": 0.3, "s": 2.0},
"xiaohongshu": {"v": 2.5, "l": 1.5, "f": 1.8, "c": 1.0, "s": 1.5},
}
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
count = 0
for topic in topics:
platforms = set()
records = db.query(PublishRecord).filter(
PublishRecord.topic_id == topic.id,
PublishRecord.action == "publish",
PublishRecord.status == "success"
).all()
for rec in records:
platforms.add(rec.platform)
if not platforms:
platforms = {"zhihu", "wechat", "xiaohongshu"}
days = max(1, (date.today() - (topic.published_at or date.today())).days)
quality = (topic.compliance_score or 70) / 100.0
for plat in platforms:
if plat not in multipliers:
platform_urls = topic.platform_urls or {}
zhihu_url = platform_urls.get("zhihu", "")
if not zhihu_url:
continue
m = re.search(r'zhuanlan\.zhihu\.com/p/(\d+)', zhihu_url)
if not m:
continue
post_id = m.group(1)
api_url = f"https://zhuanlan.zhihu.com/api/posts/{post_id}"
try:
resp = http_requests.get(api_url, headers={"User-Agent": ua}, timeout=10)
if resp.status_code != 200:
continue
m = multipliers[plat]
base = random.randint(30, 200)
growth = 1 + math.log(days + 1, 2) * 0.5
views = int(base * m["v"] * growth)
likes = int(views * quality * 0.08 * m["l"])
favs = int(likes * 0.5 * m["f"])
comm = int(views * quality * 0.02 * m["c"])
shar = int(views * quality * 0.03 * m["s"])
raw = resp.json()
existing = db.query(ContentMetrics).filter(
ContentMetrics.topic_id == topic.id,
ContentMetrics.platform == plat
ContentMetrics.platform == "zhihu"
).first()
metric_data = {
"views": raw.get("voteup_count", raw.get("views_count", 0)),
"likes": raw.get("voteup_count", 0),
"favorites": raw.get("favorite_count", 0),
"comments": raw.get("comment_count", raw.get("comments_count", 0)),
"shares": raw.get("share_count", 0),
"last_fetched": datetime.now(),
"publish_url": zhihu_url,
"data_snapshot": raw,
}
if existing:
existing.views = views
existing.likes = likes
existing.favorites = favs
existing.comments = comm
existing.shares = shar
existing.last_fetched = datetime.now()
for k, v in metric_data.items():
setattr(existing, k, v)
else:
db.add(ContentMetrics(
topic_id=topic.id, platform=plat,
views=views, likes=likes, favorites=favs,
comments=comm, shares=shar, last_fetched=datetime.now()
))
db.add(ContentMetrics(topic_id=topic.id, platform="zhihu", **metric_data))
count += 1
db.commit()
except Exception:
continue
if count:
db.commit()
logger.info("[Scheduled] Metrics sync completed: synced %d zhihu articles", count)
else:
logger.info("[Scheduled] Metrics sync: no zhihu articles to sync")
db.close()
logger.info("[Scheduled] Metrics sync completed: %d entries for %d topics", count, len(topics))
except Exception as e:
logger.exception("[Scheduled] Metrics sync failed: %s", e)