Files
mini-openclaw-v2/backend/api/risk_agent_alignment.py
T
qiaoqichaoandClaude Code d56c699ce6 chore(v2): 从兴邦预审v2白名单抽取独立可运行基座
按 docs/v2/05-implementation-plan.md §1 候选迁移表与 claude_use/T00 白名单,
从 55e2cdb 抽取 224 个文件(2.48 MB)到独立目录 F:/mini-OpenClaw-v2。

- 排除:凭据(.env/server-deploy.conf/旧DELIVERY.md)、运行数据(xingbang_data 等
  4 个 SQLite)、依赖(venv/node_modules 符号链接)、归档(_backup*/test-evidence/
  ori_file)、Office 临时文件
- 目标目录独立 git 仓库,初始恢复点;Gitea 远程与分支待 OQ-06 Q2 定案
- 未部署、未启动服务、未调用模型

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 12:58:26 +08:00

74 lines
3.8 KiB
Python

"""Normalize peer data cards without assuming an upstream/downstream dependency."""
import math
import re
from decimal import Decimal, InvalidOperation
from datetime import date
MONEY_FIELDS = {"facility.amount", "financial.total_assets", "financial.total_liabilities", "financial.operating_cashflow", "lease.total_value", "insurance.amount", "deposit.amount", "guarantee.amount"}
SCALE = {"元": Decimal("0.0001"), "万元": Decimal(1), "亿元": Decimal(10000)}
def period_key(value):
text = str(value or "")
if re.fullmatch(r"\d{4}", text):
return date(int(text), 12, 31)
if re.fullmatch(r"\d{4}-\d{2}", text):
return date.fromisoformat(text + "-01")
return date.fromisoformat(text)
def align(card, rows, project_id, requested_period=None):
config = card.get("alignment", {})
project_field = config.get("project_field", "project_id")
period_field = config.get("period_field", "")
scope_field = config.get("scope_field", "")
selection = config.get("selection", "single")
if not rows:
raise ValueError("未取得项目记录,不得解释为无风险")
if not project_field or any(str(row.get(project_field, "")) != project_id for row in rows):
raise ValueError("返回记录的项目标识缺失或不一致,请检查查询和项目关联字段")
records = []
for row in rows:
period = row.get(period_field) if period_field else card.get("period")
scope = row.get(scope_field) if scope_field else card.get("scope")
mapped, units = {}, {}
for field, source in card.get("mapping", {}).items():
value = row.get(source)
unit = card.get("field_units", {}).get(field, card.get("unit") if field in MONEY_FIELDS else None)
if value is not None and unit:
if unit not in SCALE:
raise ValueError(f"{field} 的金额单位不支持:{unit}")
try:
value = float(Decimal(str(value)) * SCALE[unit])
if not math.isfinite(value): raise ValueError("非有限值")
except (ValueError, InvalidOperation):
raise ValueError(f"{field} 金额不是有效数值")
units[field] = "万元"
mapped[field] = value
records.append({"period": period, "scope": scope, "values": mapped, "units": units, "raw": row})
target_scope = config.get("target_scope", "")
candidates = [r for r in records if not target_scope or r["scope"] == target_scope]
if not candidates:
raise ValueError("未取得指定财务口径的记录")
if len({r["scope"] for r in candidates}) > 1:
raise ValueError("返回多个财务口径,请明确目标口径,不能混合计算")
if selection in ("latest", "period", "all"):
try:
for r in candidates: period_key(r["period"])
except (ValueError, TypeError):
raise ValueError("多期记录缺少有效期间,应使用 YYYY、YYYY-MM 或 YYYY-MM-DD")
keys = [(r["period"], r["scope"]) for r in candidates]
if len(set(keys)) != len(keys):
raise ValueError("同一期间与口径存在重复记录,可能由多表关联放大行数")
if (requested_period and period_field) or selection == "period":
target = requested_period or config.get("target_period")
candidates = [r for r in candidates if str(r["period"]) == str(target)]
elif selection == "latest":
newest = max(period_key(r["period"]) for r in candidates)
candidates = [r for r in candidates if period_key(r["period"]) == newest]
if selection == "all" and not (requested_period and period_field):
return records, None
if len(candidates) != 1:
raise ValueError(f"取得 {len(candidates)} 条候选记录,请指定期间或明确唯一粒度")
return records, candidates[0]