上线版: 产品表单统一+form嵌套修复+用户管理+部署+三套叙事
- 产品编辑入口统一走 ProductFormFull(卖点/风格/人群/品牌词全字段); 修复开任务页 <form> 套 <form> 致"编辑产品"报错、改不了、跳回首个产品 - dashboard 入口卡片对齐实际路由: 系统管理(/config) 与 工作配置(/settings) 分开; settings ?tab=products 直达改用挂载后读 URL, 消除 hydration mismatch - 新增用户管理(users API/admin service/改密页) + alembic 022/023/024 - 上线部署: Dockerfile / docker-compose.prod+https / nginx https / .env.example - A8 三套正交叙事(痛点/场景/成分背书) + beige 调色去AI化 + 飞轮 text_import 高权重信号 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -46,19 +46,37 @@ def decrypt_user_key(db, operator_id: int, workspace_id: int) -> str:
|
||||
return decrypt_key(api_key_row.encrypted_key)
|
||||
|
||||
|
||||
def build_clients_and_clear_key(plain_key: str):
|
||||
def decrypt_codeproxy_key(db, operator_id: int, workspace_id: int) -> str | None:
|
||||
"""
|
||||
查用户录入的 codeproxy 备用站 key → Fernet 解密,返回 plain_key 或 None。
|
||||
备用通道:用户没录则返回 None(不抛错),build_ai_clients 会回落 env,
|
||||
主生图流程绝不因没录备用 key 而中断(apiports 主通道才是必需)。
|
||||
"""
|
||||
from app.models.workspace import UserApiKey
|
||||
from app.utils.fernet_utils import decrypt_key
|
||||
|
||||
row = db.query(UserApiKey).filter(
|
||||
UserApiKey.user_id == operator_id,
|
||||
UserApiKey.workspace_id == workspace_id,
|
||||
UserApiKey.provider == "codeproxy",
|
||||
).first()
|
||||
return decrypt_key(row.encrypted_key) if row else None
|
||||
|
||||
|
||||
def build_clients_and_clear_key(plain_key: str, alt_key: str | None = None):
|
||||
"""
|
||||
Step3: 构建 AIClients,plain_key 传入后立即由调用方置 None。
|
||||
alt_key:用户录入的 codeproxy 备用 key(可选),同样由调用方查库解密后传入。
|
||||
返回 clients 对象。
|
||||
"""
|
||||
from app.services.ai_engine.gemini_factory import build_ai_clients
|
||||
return build_ai_clients(plain_key)
|
||||
return build_ai_clients(plain_key, alt_key=alt_key)
|
||||
|
||||
|
||||
def build_product_dict(product) -> dict:
|
||||
"""把 ORM product 转成 AI 引擎所需的 dict(不含任何 key)。"""
|
||||
return {
|
||||
"id": product.id,
|
||||
"id": getattr(product, "id", None),
|
||||
"name": product.name,
|
||||
"category": product.category or "通用好物",
|
||||
"selling_points": json.loads(product.selling_points or "[]"),
|
||||
@@ -133,4 +151,7 @@ def load_flywheel_context(db, workspace_id: int, product_id: int, product_dict:
|
||||
for e in recent
|
||||
]
|
||||
ctx = aggregate_preference_context(events_dicts, product_dict, workspace_id, product_id)
|
||||
# 累积感知:补该产品累计信号总数(前端"飞轮已积累N条信号"),与展示端同口径
|
||||
from app.services.flywheel_service import count_signals
|
||||
ctx["signal_count"] = count_signals(db, workspace_id, product_id)
|
||||
return ctx.get("prompt_fragment", ""), ctx
|
||||
|
||||
Reference in New Issue
Block a user