Files
beige/backend/app/models/flywheel.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

98 lines
3.7 KiB
Python
Raw Permalink 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.
"""
app/models/flywheel.py — preference_events / ai_call_logs
Alembic 003ai_call_logs+ Alembic 004preference_events
preference_profile 二期预留,一期不建。
"""
from datetime import datetime
from sqlalchemy import (
BigInteger, DateTime, Enum, ForeignKey,
Index, Integer, String, Text, func,
)
from sqlalchemy.orm import Mapped, mapped_column
from app.constants.enums import DataOwnership, SignalType
from app.core.database import Base
class PreferenceEvent(Base):
"""
飞轮信号日志。
workspace_id + product_id 都必须有(跨公司隔离 + 按产品分开学)。
angle_label 跟着产品的文案角度走不写死基石A
"""
__tablename__ = "preference_events"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
workspace_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
product_id: Mapped[int] = mapped_column(
BigInteger, ForeignKey("products.id"), nullable=False
)
task_id: Mapped[int] = mapped_column(
BigInteger, ForeignKey("generation_tasks.id"), nullable=False
)
user_id: Mapped[int] = mapped_column(
BigInteger, ForeignKey("users.id"), nullable=False
)
signal_type: Mapped[str] = mapped_column(
Enum(SignalType, values_callable=lambda x: [e.value for e in x]),
nullable=False,
)
signal_weight: Mapped[int] = mapped_column(Integer, nullable=False)
candidate_id: Mapped[int | None] = mapped_column(BigInteger)
angle_label: Mapped[str | None] = mapped_column(String(64))
reason: Mapped[str | None] = mapped_column(Text) # 打回原因原文
signal_meta: Mapped[str | None] = mapped_column(Text) # JSON扩展用
data_ownership: Mapped[str] = mapped_column(
Enum(DataOwnership, values_callable=lambda x: [e.value for e in x]),
default=DataOwnership.CLIENT_DATA, nullable=False,
)
created_at: Mapped[datetime] = mapped_column(
DateTime, server_default=func.now(), nullable=False
)
__table_args__ = (
Index(
"idx_preference_events_ws_product_created",
"workspace_id", "product_id", "created_at",
),
)
class AiCallLog(Base):
"""
AI 调用记录usage + 排障基础)。
调用失败归因到个人 key错误码50002
绝不记录明文 key只记录 key_id。
"""
__tablename__ = "ai_call_logs"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
workspace_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
user_id: Mapped[int] = mapped_column(
BigInteger, ForeignKey("users.id"), nullable=False
)
key_id: Mapped[int | None] = mapped_column(
BigInteger, ForeignKey("user_api_keys.id")
)
task_id: Mapped[int | None] = mapped_column(
BigInteger, ForeignKey("generation_tasks.id")
)
provider: Mapped[str | None] = mapped_column(String(32))
model: Mapped[str | None] = mapped_column(String(64))
call_type: Mapped[str | None] = mapped_column(String(32)) # text/image/analyze
prompt_tokens: Mapped[int | None] = mapped_column(Integer)
completion_tokens: Mapped[int | None] = mapped_column(Integer)
success: Mapped[bool] = mapped_column(default=True, nullable=False)
error_code: Mapped[str | None] = mapped_column(String(32))
latency_ms: Mapped[int | None] = mapped_column(Integer)
created_at: Mapped[datetime] = mapped_column(
DateTime, server_default=func.now(), nullable=False
)
__table_args__ = (
Index("idx_ai_call_logs_workspace_user", "workspace_id", "user_id"),
Index("idx_ai_call_logs_task_id", "task_id"),
)