"""起点/番茄人工导出导入与归因对比。""" from __future__ import annotations import csv import json from pathlib import Path from typing import Any from muse.store import connect, default_db_path def import_ranking(path: str | Path, *, sqlite_path: str | Path | None = None) -> dict[str, Any]: source = Path(path) rows = [] with source.open(encoding="utf-8") as handle: reader = csv.DictReader(handle) for row in reader: rows.append( { "platform": row.get("platform") or row.get("平台"), "title": row.get("title") or row.get("书名"), "rank": int(row.get("rank") or row.get("名次") or 0), "votes": int(row.get("votes") or row.get("月票") or row.get("追读") or 0), "date": row.get("date") or row.get("日期"), } ) if not rows: raise ValueError("导入表为空") with connect(sqlite_path or default_db_path()) as conn: runs = [ dict(row) for row in conn.execute( "SELECT id, kind, skill_set_hash, created_at FROM runs ORDER BY created_at DESC LIMIT 20" ) ] report = { "imported": len(rows), "top": rows[0], "runs_considered": len(runs), "attribution": [ { "title": item["title"], "platform": item["platform"], "rank": item["rank"], "nearest_run": runs[0]["id"] if runs else None, "skill_set_hash": runs[0]["skill_set_hash"] if runs else None, } for item in rows[:5] ], } return report def write_attribution_report(report: dict[str, Any], dest: str | Path) -> Path: target = Path(dest) target.parent.mkdir(parents=True, exist_ok=True) lines = ["# 榜单归因", ""] lines.append(f"导入 {report['imported']} 行。") for item in report["attribution"]: lines.append( f"- {item['platform']}《{item['title']}》第 {item['rank']} 名 → run `{item['nearest_run']}` skill_set `{item['skill_set_hash']}`" ) target.write_text("\n".join(lines) + "\n", encoding="utf-8") return target