Files
beige/backend/scripts/seed_data.py
yangqianqian 6a2632da70 baseline: Clover 独立仓库首次基线提交
将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。
当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包),
M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 11:30:22 +08:00

157 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
scripts/seed_data.py — 初始化北哥 workspace 种子数据
建3账号(admin/supervisor/operator) + workspace_members + 预置素颜霜 + 5条违禁词
幂等:已存在则跳过,可重复跑。
用法cd backend && python3 scripts/seed_data.py
"""
import json
import os
import sys
# 把 backend/ 加入 path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app.core.config import get_settings # noqa: E402 — path must be set first
from app.core.database import SessionLocal # noqa: E402
from app.models.user import User # noqa: E402
from app.models.workspace import Workspace, WorkspaceMember # noqa: E402
from app.models.product import Product, BannedWord # noqa: E402
from app.services.auth_service import hash_password # noqa: E402
get_settings() # 触发 .env 校验,缺变量早报错
WORKSPACE_NAME = "北哥小红书车间"
WORKSPACE_SLUG = "beige-xhs"
USERS = [
{"username": "admin", "email": "admin@clover.local", "password": "Clover2026!", "role": "admin"},
{"username": "supervisor", "email": "supervisor@clover.local", "password": "Clover2026!", "role": "supervisor"},
{"username": "operator", "email": "operator@clover.local", "password": "Clover2026!", "role": "operator"},
]
PRODUCT = {
"name": "素颜霜(预置样本)",
"category": "素颜霜",
"source": "preset",
"selling_points": json.dumps(["遮瑕提亮", "持妆", "养肤成分"], ensure_ascii=False),
"style_tone": "素人分享、真实不浮夸",
"text_angles": json.dumps(["痛点切入", "成分党", "使用场景", "质地肤感", "平价替代"], ensure_ascii=False),
"custom_prompt": None,
"is_active": True,
}
BANNED_WORDS = [
{"word": "美白", "level": "auto_fix", "replacement": "提亮肤色"},
{"word": "祛斑", "level": "auto_fix", "replacement": "改善暗沉"},
{"word": "速效", "level": "soft_warn", "replacement": "温和渐进"},
{"word": "医用", "level": "hard_block", "replacement": None},
{"word": "药妆", "level": "hard_block", "replacement": None},
]
def run():
db = SessionLocal()
try:
# ── workspace ──────────────────────────────────────
ws = db.query(Workspace).filter(Workspace.slug == WORKSPACE_SLUG).first()
if not ws:
ws = Workspace(name=WORKSPACE_NAME, slug=WORKSPACE_SLUG, is_active=True)
db.add(ws)
db.flush()
print(f"[+] workspace 已建: {ws.name} (id={ws.id})")
else:
print(f"[=] workspace 已存在: id={ws.id}")
# ── users + members ────────────────────────────────
for u_spec in USERS:
user = db.query(User).filter(User.username == u_spec["username"]).first()
if not user:
user = User(
username=u_spec["username"],
email=u_spec["email"],
hashed_password=hash_password(u_spec["password"]),
is_active=True,
)
db.add(user)
db.flush()
print(f"[+] user: {user.username}")
else:
print(f"[=] user 已存在: {user.username}")
mem = db.query(WorkspaceMember).filter(
WorkspaceMember.workspace_id == ws.id,
WorkspaceMember.user_id == user.id,
).first()
if not mem:
db.add(WorkspaceMember(workspace_id=ws.id, user_id=user.id, role=u_spec["role"]))
print(f" -> 绑定 role={u_spec['role']}")
# ── 预置素颜霜 ─────────────────────────────────────
prod = db.query(Product).filter(
Product.workspace_id == ws.id, Product.name == PRODUCT["name"]
).first()
if not prod:
prod = Product(workspace_id=ws.id, **PRODUCT)
db.add(prod)
print(f"[+] product: {prod.name}")
else:
print(f"[=] product 已存在: {prod.name}")
# ── 违禁词 ─────────────────────────────────────────
for bw_spec in BANNED_WORDS:
existing = db.query(BannedWord).filter(
BannedWord.workspace_id == ws.id, BannedWord.word == bw_spec["word"]
).first()
if not existing:
db.add(BannedWord(workspace_id=ws.id, **bw_spec))
print(f"[+] banned_word: {bw_spec['word']} ({bw_spec['level']})")
else:
print(f"[=] banned_word 已存在: {bw_spec['word']}")
# ── user_api_keysR3明文key只在加密瞬间用不打印不落明文──
apiports_key = os.environ.get("APIPORTS_KEY", "").strip()
if apiports_key:
from app.models.workspace import UserApiKey
from app.utils.fernet_utils import encrypt_key
for u_spec in USERS:
u = db.query(User).filter(User.username == u_spec["username"]).first()
if not u:
continue
existing_key = db.query(UserApiKey).filter(
UserApiKey.user_id == u.id,
UserApiKey.workspace_id == ws.id,
UserApiKey.provider == "apiports",
).first()
encrypted = encrypt_key(apiports_key)
last4 = apiports_key[-4:] if len(apiports_key) >= 4 else "****"
if existing_key:
existing_key.encrypted_key = encrypted
existing_key.key_last4 = last4
print(f"[=] api_key updated: {u.username} apiports ***{last4}")
else:
db.add(UserApiKey(
user_id=u.id,
workspace_id=ws.id,
provider="apiports",
encrypted_key=encrypted,
key_last4=last4,
))
print(f"[+] api_key: {u.username} apiports ***{last4}")
apiports_key = None # 明文用完即清基石B
else:
print("[!] APIPORTS_KEY 未设置,跳过 user_api_keys 录入(部署时需手动录入或重跑种子)")
db.commit()
print("\n种子数据初始化完成。")
except Exception as e:
db.rollback()
print(f"[ERROR] {e}")
raise
finally:
db.close()
if __name__ == "__main__":
run()