75 lines
2.6 KiB
Python
75 lines
2.6 KiB
Python
"""手工重建客户画像:中期记忆 → 长期事实 → 画像 + 版本快照。
|
||||
|
|
|
|||
|
|
用法:
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
# 重建一个客户
|
|||
|
|
python tools/rebuild_profile.py 9001
|
|||
|
|
|
|||
|
|
# 重建全部有记忆的客户
|
|||
|
|
python tools/rebuild_profile.py --all
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
为什么需要这个入口:画像组装目前没有自动触发(记忆写入后不会立刻重建画像),
|
|||
|
|
在把它接上 Worker 事件之前,这是唯一的触发方式,也便于运维排查"画像为什么没更新"。
|
|||
|
|
|
|||
|
|
关于输出里的 `reason=profile_row_not_opened`:客户尚未开户时不会创建画像行
|
|||
|
|
(`trade_account` 等身份字段是 NOT NULL,属注册/开户流程所有),这是**正确行为**而非失败。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import argparse
|
|||
|
|
import asyncio
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
from sqlalchemy import select
|
|||
|
|
|
|||
|
|
from app.infrastructure.db import SessionFactory
|
|||
|
|
from app.model.memory import MemoryUnit
|
|||
|
|
from app.service.profile_assembly_service import ProfileAssemblyService
|
|||
|
|
|
|||
|
|
sys.stdout.reconfigure(errors="replace")
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def rebuild_one(customer_id: int) -> None:
|
|||
|
|
async with SessionFactory() as session:
|
|||
|
|
async with session.begin():
|
|||
|
|
outcome = await ProfileAssemblyService(session).rebuild(customer_id)
|
|||
|
|
print(f"\n== 客户 {customer_id} ==")
|
|||
|
|
if outcome.get("profile") is None:
|
|||
|
|
print(f" 未重建画像:{outcome.get('reason')}"
|
|||
|
|
f"(尚未开户;已提升事实 {len(outcome.get('promoted_keys') or [])} 条)")
|
|||
|
|
else:
|
|||
|
|
print(f" 提升事实:{outcome.get('promoted_keys')}")
|
|||
|
|
print(f" 画像内容:{outcome.get('profile')}")
|
|||
|
|
print(f" 生成依据:{outcome.get('generation_basis')}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def main() -> int:
|
|||
|
|
parser = argparse.ArgumentParser(description="重建客户画像")
|
|||
|
|
parser.add_argument("customer_id", nargs="?", type=int, help="客户 id")
|
|||
|
|
parser.add_argument("--all", action="store_true", help="重建全部有记忆的客户")
|
|||
|
|
args = parser.parse_args()
|
|||
|
|
|
|||
|
|
if args.all:
|
|||
|
|
async with SessionFactory() as session:
|
|||
|
|
rows = list(await session.scalars(
|
|||
|
|
select(MemoryUnit.customer_id).distinct()
|
|||
|
|
))
|
|||
|
|
targets = [int(row) for row in rows]
|
|||
|
|
if not targets:
|
|||
|
|
print("没有任何客户有记忆数据,无需重建")
|
|||
|
|
return 0
|
|||
|
|
print(f"将重建 {len(targets)} 个客户:{targets}")
|
|||
|
|
for customer_id in targets:
|
|||
|
|
await rebuild_one(customer_id)
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
if args.customer_id is None:
|
|||
|
|
parser.print_help()
|
|||
|
|
return 2
|
|||
|
|
await rebuild_one(args.customer_id)
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
sys.exit(asyncio.run(main()))
|