diff --git a/sources.py b/sources.py index 9ed5a20..44c95be 100644 --- a/sources.py +++ b/sources.py @@ -1211,18 +1211,31 @@ def company_reviews(codes, ds: str, *, read_pg=None) -> dict: ran_day, age = None, None k = _prefix_any(str(r.get("ts_code"))) brain = sm.get("brain") or {} - out[k] = {"period": r.get("period"), "review_version": r.get("review_version"), + if age is not None and age < 0: + age = 0 # 报告运行日晚于数据日(今早刚跑):算零天,不算负数 + out[k] = {"period": _clean_str(r.get("period")), "review_version": _clean_str(r.get("review_version")), "overall": sm.get("overall"), "groups": sm.get("groups"), "valuation": sm.get("valuation"), "doubt_hard": bool(sm.get("doubt_hard")), "quality_reasons": sm.get("quality_reasons") or [], "grade_counts": sm.get("grade_counts") or _count_grades(grades), "grade_line": sm.get("grade_line"), "thesis": sm.get("thesis"), "confidence": sm.get("confidence"), "invalidation": sm.get("invalidation"), "antithesis": sm.get("antithesis"), "catalyst": sm.get("catalyst"), - "brain_status": r.get("brain_status") or brain.get("status"), "brain_used": bool(r.get("brain_used")), + "brain_status": _clean_str(r.get("brain_status")) or _clean_str(brain.get("status")), + "brain_used": bool(r.get("brain_used")) if r.get("brain_used") not in (None, "") and r.get("brain_used") == r.get("brain_used") else False, "ran_at": ran_day.isoformat() if ran_day else None, "age_days": age, "report_url": f"{config.AKG_API_BASE}{sm.get('report_path') or '/company/' + str(r.get('ts_code')) + '/review'}"} return out +def _clean_str(v): + """空列经 pandas 会变成 NaN(浮点),JSON 序列化直接失败;统一收成 None。""" + if v is None: + return None + if isinstance(v, float) and v != v: + return None + s = str(v).strip() + return s or None + + def _count_grades(grades) -> dict: out = {"好": 0, "中": 0, "差": 0, "证据不足": 0} for v in (grades or {}).values():